EF Migration fails due to GUID foreign key - c#

I have the following models in my .NET Core 2.1 application:
public class Product
{
[Key]
public Guid ProductId { get; set; }
public virtual ICollection<Favourite> Favourites { get; set; }
}
public class Retailer
{
[Key]
public Guid BusinessId {get; set;}
public virtual ICollection<Favourite> Favourites { get; set; }
}
public class Favourite
{
[Key]
public Guid FavouriteId { get; set; }
[ForeignKey("Retailer_BusinessId")]
public virtual Retailer Business { get; set; }
[ForeignKey("Product_ProductId")]
public virtual Product Product { get; set; }
}
When trying to run an EF migration, I get the following error:
The relationship from 'Favourite.Business' to 'Retailer.Favourites'
with foreign key properties {'Retailer_BusinessId' : Nullable}
cannot target the primary key {'BusinessId' : Guid} because it is not
compatible. Configure a principal key or a set of compatible foreign
key properties for this relationship.
I suspect it's because I'm using Guid's as my keys in the foreign tables. How do I tell EF that?

It looks like EF expects the ForeignKey attribute to refer to the navigation property. I was able to reproduce the error you were getting and after making the following change, it migrated successfully.
public class Favourite
{
[Key]
public Guid FavouriteId { get; set; }
[ForeignKey("Business")]
public Guid BusinessId { get; set; }
[ForeignKey("Product")]
public Guid ProductId { get; set; }
public virtual Retailer Business { get; set; }
public virtual Product Product { get; set; }
}
EDIT: The way you were doing it was close, but you need to have the property and then specify just the property's name in the ForeignKey attribute.
public class Favourite
{
[Key]
public Guid FavouriteId { get; set; }
public Guid BusinessId { get; set; }
public Guid ProductId { get; set; }
[ForeignKey("BusinessId")]
public virtual Retailer Business { get; set; }
[ForeignKey("ProductId")]
public virtual Product Product { get; set; }
}

Related

Entity Framework - Foreign keys and Navigation Properties

I need your help understanding relationships between tables. I´m having a hard time trying to understand the usage/need of using navigation properties with foreign key properties to define relantionships.
Given the 2 classes below,
public class Person
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public string Name{ get; set; }
}
public class Package
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid AccountId { get; set; }
public virtual Person Account { get; set; }
public Guid ShipperId { get; set; }
public virtual Client Shipper { get; set; }
[Required]
public Guid ReceiverId { get; set; }
public virtual Client Receiver { get; set; }
}
If I try to update the database, I get the error
Introducing FOREIGN KEY constraint 'FK_' on table 'Packages' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
On the other hand if I remove the property public Guid ....Id { get; set; }, the database is created with the foreign keys but the [Required] annotation as no effect.
What´s the difference between including a Guid property and not?
try to use this classes:
public class Person
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public string Name{ get; set; }
[InverseProperty(nameof(Package.Account))]
public virtual ICollection<Package> Packages { get; set; }
}
public class Package
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public Guid AccountId { get; set; }
[ForeignKey(nameof(AccountId))]
[InverseProperty("Packages")]
public virtual Person Account { get; set; }
}
and use this code in dbcontext:
modelBuilder.Entity<Package>(entity =>
{
entity.HasOne(d => d.Person)
.WithMany(p => p.Packages)
.HasForeignKey(d => d.AccountId)
.OnDelete(DeleteBehavior.ClientSetNull);
});

Set a foreign key for same entity in ef core

I want to build parent child entities for the same entity class in Entity Framework Core.
So I have a entity like this:
public class Definition
{
public int Id{ get; set; }
public int ParentId { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
}
I want to set ParentId as foreign key that refers another Definition Entity as parent entity.
How can I do this?
Thanks
add a foreign key attribute for parent defination
public class Definition
{
[Key]
public int Id{ get; set; }
public int? ParentId { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
[ForeignKey("ParentId")]
public virtual Definition ParentDefinition { get; set; }
}

Having a hard time understanding how cascade delete works and how to configure relationships

So, I have the dependent entity ArtItem, with parent class Location, which is a dependent entity of Company, which is a dependent entity of Country. ArtItem is also dependent on Artist and Artist is dependent on Country.
public class Country
{
[Required]
public int Id { get; set; }
}
public class Company
{
public Country Country { get; set; }
[Required]
public int CountryId { get; set; }
[Required]
public int Id { get; set; }
}
public class Location
{
[Required]
public int Id { get; set; }
public Company Company { get; set; }
public int CompanyId { get; set; }
//public List<ArtItem> ArtItems { get; set; }
}
public class ArtItem
{
public Artist Artist { get; set; }
public int ArtistId { get; set; }
[Required]
public int Id { get; set; }
public Location Location { get; set; }
[Required]
public int LocationId { get; set; }
}
public class Artist
{
public Country Country { get; set; }
[Required]
public int CountryId { get; set; }
[Required]
public int Id { get; set; }
}
My issue is that whenever I try to do update-database in powershell, I get the error Introducing FOREIGN KEY constraint 'FK_ArtItems_Locations_LocationId' on table 'ArtItems' may cause cycles or multiple cascade paths..
I tried configuring the relationship in my DbContext class,
.
but to no avail. I simply don't understand how I'm supposed to configure relationships in EF Core, or how modelBuilder works. I would highly appreciate an explanation on how to avoid this error and what actually causes it. I thought that having a navigation property and a foreign key defined would be enough for EF Core to properly generate the relationships. I tried the online documentation for EF Core on relationships to no avail.
Help is much appreciated.
Thanks in advance.

EF relation one-to-two

I'm having some troubles when saving in the database a model with a little complex relationship.
The UML of the classes is:
The classes definition are:
public abstract class EntityBase
{
public virtual Guid Id { get; set; }
}
public class LoanRequest : EntityBase
{
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public virtual Applicant Applicant1 { get; set; }
public virtual Applicant Applicant2 { get; set; }
}
public class Applicant
{
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public Guid LoanRequestId { get; set; }
[ForeignKey("LoanRequestId")]
public virtual LoanRequest LoanRequest { get; set; }
public virtual ICollection<MonthlyIncome> Incomes { get; set; }
}
public class MonthlyIncome
{
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public Guid ApplicantId { get; set; }
[ForeignKey("ApplicantId")]
public virtual Applicant Applicant { get; set; }
}
I'm able to run a migration and looking into the database the tables and columns created by the framework seems fine to me. But, when saving an exception happens. The exception is:
Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values
I've been searching for a solution on the internet and I can't see where my problem is. Any suggestions? Thanks!
After several tryings I was able to find a solution. Changing the applicant definition to:
public class Applicant
{
[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public virtual ICollection<MonthlyIncome> Incomes { get; set; }
}
was all I needed

ef modelBuilder force foreignkey a or foreignkey b

OK.
Background.
I was initially trying to make EF models along the lines of:
public class Person
{
[Key]
public Guid ID { get; set; }
public string Name { get; set; }
public Guid PhoneID { get; set; }
public virtual ICollection<Phone> Phones { get; set; }
}
public class Org
{
[Key]
public Guid ID { get; set; }
public string Name { get; set; }
public Guid PhoneID { get; set; }
public virtual ICollection<Phone> Phones { get; set; }
}
public class Phone
{
[Key]
public Guid ID { get; set; }
public string Number { get; set; }
public Guid EntityID { get; set; }
[ForeignKey("EntityID")]
public virtual User User { get; set; }
[ForeignKey("EntityID")]
public virtual Org Org { get; set; }
}
But I now (mostly) realize that this causes an issue with Foreign Key relationship integrity in SQL Server. So to correct this, I altered the Phone class to:
public class Phone
{
[Key]
public Guid ID { get; set; }
public string Number { get; set; }
public Guid? PersonID { get; set; }
public Guid? OrgID { get; set; }
[ForeignKey("PersonID")]
public virtual User User { get; set; }
[ForeignKey("OrgID")]
public virtual Org Org { get; set; }
}
Question.
How can I enforce / map a rule using modelbuilder / Fluent API to ensure a Phone object has either a PersonID or an OrgID?
Edit:
I do realise that this is creating a data integrity rule that I would be unable to do if I was designing the database in SQL Server, but to me it seems that EF has the potential flexibility to take database design to the next level.
I see EF (Code-First especially) as Microsoft's next big leap in their software development strategy. IMHO this is as big a leap as the introduction of .Net (Now there is a statement that should generate some debate!), that being moving the database design away from the database itself & integrating it in with the managed code.

Categories