I've just started using EF code first, so I'm a total beginner in this topic.
I wanted to create relations between Teams and Matches:
1 match = 2 teams (home, guest) and result.
I thought it's easy to create such a model, so I started coding:
public class Team
{
[Key]
public int TeamId { get; set;}
public string Name { get; set; }
public virtual ICollection<Match> Matches { get; set; }
}
public class Match
{
[Key]
public int MatchId { get; set; }
[ForeignKey("HomeTeam"), Column(Order = 0)]
public int HomeTeamId { get; set; }
[ForeignKey("GuestTeam"), Column(Order = 1)]
public int GuestTeamId { get; set; }
public float HomePoints { get; set; }
public float GuestPoints { get; set; }
public DateTime Date { get; set; }
public virtual Team HomeTeam { get; set; }
public virtual Team GuestTeam { get; set; }
}
And I get an exception:
The referential relationship will result in a cyclical reference that is not allowed. [ Constraint name = Match_GuestTeam ]
How can I create such a model, with 2 foreign keys to the same table?
Try this:
public class Team
{
public int TeamId { get; set;}
public string Name { get; set; }
public virtual ICollection<Match> HomeMatches { get; set; }
public virtual ICollection<Match> AwayMatches { get; set; }
}
public class Match
{
public int MatchId { get; set; }
public int HomeTeamId { get; set; }
public int GuestTeamId { get; set; }
public float HomePoints { get; set; }
public float GuestPoints { get; set; }
public DateTime Date { get; set; }
public virtual Team HomeTeam { get; set; }
public virtual Team GuestTeam { get; set; }
}
public class Context : DbContext
{
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Match>()
.HasRequired(m => m.HomeTeam)
.WithMany(t => t.HomeMatches)
.HasForeignKey(m => m.HomeTeamId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Match>()
.HasRequired(m => m.GuestTeam)
.WithMany(t => t.AwayMatches)
.HasForeignKey(m => m.GuestTeamId)
.WillCascadeOnDelete(false);
}
}
Primary keys are mapped by default convention. Team must have two collection of matches. You can't have single collection referenced by two FKs. Match is mapped without cascading delete because it doesn't work in these self referencing many-to-many.
It's also possible to specify the ForeignKey() attribute on the navigation property:
[ForeignKey("HomeTeamID")]
public virtual Team HomeTeam { get; set; }
[ForeignKey("GuestTeamID")]
public virtual Team GuestTeam { get; set; }
That way you don't need to add any code to the OnModelCreate method
I know it's a several years old post and you may solve your problem with above solution. However, i just want to suggest using InverseProperty for someone who still need. At least you don't need to change anything in OnModelCreating.
The below code is un-tested.
public class Team
{
[Key]
public int TeamId { get; set;}
public string Name { get; set; }
[InverseProperty("HomeTeam")]
public virtual ICollection<Match> HomeMatches { get; set; }
[InverseProperty("GuestTeam")]
public virtual ICollection<Match> GuestMatches { get; set; }
}
public class Match
{
[Key]
public int MatchId { get; set; }
public float HomePoints { get; set; }
public float GuestPoints { get; set; }
public DateTime Date { get; set; }
public virtual Team HomeTeam { get; set; }
public virtual Team GuestTeam { get; set; }
}
You can read more about InverseProperty on MSDN: https://msdn.microsoft.com/en-us/data/jj591583?f=255&MSPPError=-2147217396#Relationships
You can try this too:
public class Match
{
[Key]
public int MatchId { get; set; }
[ForeignKey("HomeTeam"), Column(Order = 0)]
public int? HomeTeamId { get; set; }
[ForeignKey("GuestTeam"), Column(Order = 1)]
public int? GuestTeamId { get; set; }
public float HomePoints { get; set; }
public float GuestPoints { get; set; }
public DateTime Date { get; set; }
public virtual Team HomeTeam { get; set; }
public virtual Team GuestTeam { get; set; }
}
When you make a FK column allow NULLS, you are breaking the cycle. Or we are just cheating the EF schema generator.
In my case, this simple modification solve the problem.
InverseProperty in EF Core makes the solution easy and clean.
InverseProperty
So the desired solution would be:
public class Team
{
[Key]
public int TeamId { get; set;}
public string Name { get; set; }
[InverseProperty(nameof(Match.HomeTeam))]
public ICollection<Match> HomeMatches{ get; set; }
[InverseProperty(nameof(Match.GuestTeam))]
public ICollection<Match> AwayMatches{ get; set; }
}
public class Match
{
[Key]
public int MatchId { get; set; }
[ForeignKey(nameof(HomeTeam)), Column(Order = 0)]
public int HomeTeamId { get; set; }
[ForeignKey(nameof(GuestTeam)), Column(Order = 1)]
public int GuestTeamId { get; set; }
public float HomePoints { get; set; }
public float GuestPoints { get; set; }
public DateTime Date { get; set; }
public Team HomeTeam { get; set; }
public Team GuestTeam { get; set; }
}
This is because Cascade Deletes are enabled by default. The problem is that when you call a delete on the entity, it will delete each of the f-key referenced entities as well. You should not make 'required' values nullable to fix this problem. A better option would be to remove EF Code First's Cascade delete convention:
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
It's probably safer to explicitly indicate when to do a cascade delete for each of the children when mapping/config. the entity.
I know this is pretty old question but coming here in 2021 with EF Core > 3 solution below worked for me.
Make sure to make foreign keys nullable
Specify default behavior on Delete
public class Match
{
public int? HomeTeamId { get; set; }
public int? GuestTeamId { get; set; }
public float HomePoints { get; set; }
public float GuestPoints { get; set; }
public DateTime Date { get; set; }
public Team HomeTeam { get; set; }
public Team GuestTeam { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Match>()
.HasRequired(m => m.HomeTeam)
.WithMany(t => t.HomeMatches)
.HasForeignKey(m => m.HomeTeamId)
.OnDelete(DeleteBehavior.ClientSetNull);
modelBuilder.Entity<Match>()
.HasRequired(m => m.GuestTeam)
.WithMany(t => t.AwayMatches)
.HasForeignKey(m => m.GuestTeamId)
.OnDelete(DeleteBehavior.ClientSetNull);
}
Related
I crete table in asp.net mvc but when i crete the migration this error message show
Introducing FOREIGN KEY constraint 'FK_dbo.DailyTransactions_dbo.Contracts_ContractId' on table 'DailyTransactions' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.
this is DailyTransactions table :
public class DailyTransactions
{
[Key]
public int DailyTransactions_Id { get; set; }
public double Account { get; set; }
public string Account_Name { get; set; }
public double Debit { get; set; }
public double Credit { get; set; }
public DateTime Date { get; set; }
public string Remarks { get; set; }
public int CustomerId { get; set; }
[ForeignKey("CustomerId")]
public virtual Customers customers { get; set; }
public int ContractId { get; set; }
[ForeignKey("ContractId")]
public virtual Contracts contracts { get; set; }
}
and this contract table :
public class Contracts
{
[Key]
public int Contracts_Id { get; set; }
public int Contract_Num { get; set; }
public DateTime Contract_Start { get; set; }
public DateTime Contract_End { get; set; }
public string Status { get; set; }
public string TypeOfRent { get; set; }
public double AmountOfRent { get; set; }
public double Total { get; set; }
public int CustomerId { get; set; }
[ForeignKey("CustomerId")]
public virtual Customers customers { get; set; }
public int sectionsId { get; set; }
[ForeignKey("sectionsId")]
public virtual Sections sections { get; set; }
}
Try to turn off CascadeDelete for DailyTransactions and Contracts:
modelBuilder.Entity<DailyTransactions>()
.HasRequired(c => c.Contracts)
.WithMany()
.WillCascadeOnDelete(false);
For example:
public class YourDBContext: DbContext
{
public YourDBContext(): base()
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<DailyTransactions>()
.HasRequired(c => c.Contracts)
.WithMany()
.WillCascadeOnDelete(false);
}
}
I have a problem with my entities. I'm using EF code-first migrations and the migrations are failing with this error:
Introducing FOREIGN KEY constraint 'FK_OrdersChildsProducts_Orders_OrderId' on table 'OrdersChildsProducts' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Here's my PersonJceProfile entity :
[Table("PersonJceProfiles")]
public class PersonJceProfile : BaseEntity
{
[ForeignKey("Ces")]
public int? CeId { get; set; }
public ICollection<Child> Children { get; set; }
public Order Order { get; set; }
public PersonJceProfile()
{
Children = new List<Child>();
}
}
Here's my Order entity :
[Table("Orders")]
public class Order : BaseEntity
{
[Key]
public int Id { get; set; }
//ForeignKey
[Required]
[ForeignKey("PersonJceProfiles")]
public int PersonJceProfileId { get; set; }
[Required]
public int OrderStatus { get; set; }
[Required]
public bool IsSecurePayment { get; set; }
public int LeftToPayPersonOrder { get; set; }
public string Delivery { get; set; }
public ICollection<OrderChildProduct> OrderChildProduct { get; set; }
public Order()
{
OrderChildProduct = new Collection<OrderChildProduct>();
}
}
Here's my Child entity :
[Table("Childrens")]
public class Child :BaseEntity
{
[Key]
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public DateTime? BirthDate { get; set; }
[Required]
public string Gender { get; set; }
public bool? IsActif { get; set; }
public decimal AmountParticipationCe { get; set; }
public bool? IsRegrouper { get; set; }
[Required]
[ForeignKey("PersonJceProfiles")]
public int PersonJceProfileId { get; set; }
}
Here's my Product Entity
public class Product : Good
{
public string File { get; set; }
public bool? IsDisplayedOnJCE { get; set; }
public bool? IsBasicProduct { get; set; }
public int? PintelSheetId { get; set; }
public int OriginId { get; set; }
[Required]
[ForeignKey("Suppliers")]
public int SupplierId { get; set; }
}
Here's my OrderChildProduct entity :
[Table("OrdersChildsProducts")]
public class OrderChildProduct
{
public int OrderId { get; set; }
public int ChildId { get; set; }
public int ProductId { get; set; }
public int LeftToPayChildOrder { get; set; }
public Order Order { get; set; }
public Child Child { get; set; }
public Product Product { get; set; }
}
Here's my context :
modelBuilder.Entity<OrderChildProduct>().HasKey(ccp => new { ccp.OrderId, ccp.ChildId, ccp.ProductId });
I suppose i do destro a relationship like this :
modelBuilder.Entity<Entity>()
.HasRequired(c => c.ForeignKey)
.WithMany()
.WillCascadeOnDelete(false);
but I can't see between which. Because
When I delete PersonJceProfiles : Order must be deleted - OrderChildProduct must be deleted - Child must be deleted
When I delete Order : OrderChildProduct must be deleted
When I delete Order childProduct : nothing must be deleted expect himself
What am I doing wrong? Thanks
The error is self described. You must configure the relationships in the OrderChildProduct table like:
entity.HasOne(p => p.Order)
.WithMany(p => p.OrderChildProduct)
.HasForeignKey(p => p.OrderId)
.OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict);
You can use either Restrict or Cascade depending on your requirements.
Also the other 2 relationships must be defined as well.
This is not an error. This is more like a warning... the way EF tells you that it doesn't fully understand the relationships and you must configure them manually.
I've been for a while trying to find out why the Include clause is not loading the related collection: I have two classes with a one-to-many relationship:
public class AgencyNote : IAutId
{
[Key]
public int aut_id { get; set; }
public string Comment { get; set; }
[DisplayName("Note Created Date")]
public DateTime NoteDate { get; set; }
[DisplayName("Contact Date")]
public DateTime ContactDate { get; set; }
[ForeignKey("tbl_agency")]
public int AgencyId { get; set; }
[DisplayName("User")]
public string RipsUser { get; set; }
public virtual ICollection<AgencyNoteAttachment> AgencyNoteAttachments { get; set; }
public virtual tbl_agency tbl_agency { get; set; }
}
and
public class AgencyNoteAttachment
{
[Key]
public int aut_id { get; set; }
public string Url { get; set; }
public string FileName { get; set; }
public int AgencyNoteId { get; set; }
[NotMapped]
[ForeignKey("AgencyNoteId")]
public virtual AgencyNote AgencyNote { get; set; }
}
Context class:
public DbSet<AgencyNote> AgencyNotes { get; set; }
public DbSet<AgencyNoteAttachment> AgencyNoteAttachments { get; set; }
This is the action where I'm using the Include clause:
private IQueryable<AgencyNote> GetNotes(int agencyId)
{
return _ctx.AgencyNotes
.Include(a => a.tbl_agency)
.Include(a => a.AgencyNoteAttachments)
.OrderByDescending(f => f.NoteDate)
.Where(x => x.AgencyId == agencyId);
}
I'm getting AgencyNotesAttachments always null from this action even if I know it's not null, what's going on? Any question let me know...
If you add just the navigation properties between the related entities, then EF will create the FK column for you in the AgencyNoteAttachment table. Now, EF by convention can interpret AgencyNoteId is the FK of that relationship, but is good idea do that explicitly as you already have in your model or using ForeignKey attribute on FK property:
public class AgencyNoteAttachment
{
[Key]
public int aut_id { get; set; }
public string Url { get; set; }
public string FileName { get; set; }
[ForeignKey("AgencyNote")]
public int AgencyNoteId { get; set; }
public virtual AgencyNote AgencyNote { get; set; }
}
If you want to learn more about conventions, take a look this link
I've posted a question in Programmers: https://softwareengineering.stackexchange.com/questions/315857/entity-framework-code-first-c-class-separation-and-eav
One solution to the problem is Table Splitting in Entity Framework. So far, I've seen how to do this with 2 entities, but not with 3 or more.
Here are the models I want to share a same table with:
[Table("Tournament")]
public partial class PGTournament : IImageable
{
public int Id { get; set; }
public string Name { get; set; }
public GameGenre GameGenre { get; set; }
public TournamentFormat TournamentFormat { get; set; }
public TournamentStatus Status { get; set; }
public string Description { get; set; }
public virtual List<PrizePool> Prizes { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public virtual List<Participants.Participant> Participants { get; set; }
public decimal Cost { get; set; }
public string Streaming { get; set; }
public int? ChallongeTournamentId { get; set; }
public string Bracket { get; set; }
public virtual List<TournamentMatch> Matches { get; set; }
public int MainImageId { get; set; }
public virtual Media MainImage { get; set; }
public bool IsFollowUp { get; set; }
public int? FollowUpTournamentId { get; set; }
[ForeignKey("FollowUpTournamentId")]
public virtual PGTournament FollowUptournament { get; set; }
public int MediaID { get; set; }
public int MainImageID { get; set; }
//Properties that share same table:
public virtual TournamentOrganizer Organizer { get; set; } //Change to Organizer
public virtual TournamentOrganizerSetting OrganizerSetting { get; set; }
public virtual TournamentSettings TournamentSettings { get; set; }
public virtual TournamentRules Rules { get; set; }
}
All the properties you see that are virtual and don't have a List<> as their type, I want them to share a same table (If it is possible).
[Table("Tournament")]
public partial class TournamentOrganizer
{
public int Id { get; set; }
public string Name { get; set; }
public string UserId { get; set; }
[ForeignKey("UserId")]
public AppUser User { get; set; }
public int LogoId { get; set; }
[ForeignKey("LogoId")]
public Media Logo { get; set; }
public virtual TournamentOrganizerSetting Settings { get; set; }
public virtual TournamentRules Rules { get; set; }
public virtual TournamentSettings TournamentSettings { get; set; }
public virtual PGTournament Tournament { get; set; }
}
[Table("Tournament")]
public partial class TournamentSettings
{
public int Id { get; set; }
public string Address { get; set; }
public string LocationGoogleMaps { get; set; }
public bool isOnline { get; set; }
public int MaxPlayers { get; set; }
public List<TournamentAssistant> TournamentAssistants { get; set; }
public virtual TournamentOrganizer Organizer { get; set; } //Change to Organizer
public virtual TournamentRules Rules { get; set; }
public virtual TournamentOrganizerSetting OrganizerSettings { get; set; }
public virtual PGTournament Tournament { get; set; }
}
[Table("Tournament")]
public partial class TournamentOrganizerSetting
{
public int Id { get; set; }
public string Location { get; set; }
//Properties that share same table:
public virtual TournamentOrganizer Organizer { get; set; } //Change to Organizer
public virtual TournamentRules Rules { get; set; }
public virtual TournamentSettings TournamentSettings { get; set; }
public virtual PGTournament Tournament { get; set; }
}
[Table("Tournament")]
public partial class TournamentRules
{
public int Id { get; set; }
public string Bans { get; set; }
public string Allowed { get; set; }
public string Description { get; set; }
public string FileName { get; set; }
public string FilePath { get; set; }
//Properties that share same table:
public virtual TournamentOrganizer Organizer { get; set; } //Change to Organizer
public virtual TournamentOrganizerSetting OrganizerSetting { get; set; }
public virtual TournamentSettings TournamentSettings { get; set; }
public virtual PGTournament Tournament { get; set; }
}
I don't know why the classes are partial. I've been following several tutorials over the Internet, such as this: http://www.c-sharpcorner.com/UploadFile/ff2f08/table-splitting-in-entity-framework-6-code-first-approach/
I can't get them to work.
I have even tried this in the DbModelBuilder:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<PGTournament>().ToTable("Tournament");
modelBuilder.Entity<PGTournament>()
.HasKey(e => e.Id)
.HasOptional(e => e.FollowUptournament)
.WithMany();
modelBuilder.Entity<PGTournament>()
.HasKey(e => e.Id)
.HasRequired(e => e.Organizer)
.WithRequiredDependent(e => e.Organizer)
modelBuilder.Entity<TournamentOrganizer>()
.HasKey(e => e.Id)
.HasRequired(e => e.Settings)
.WithRequiredDependent(e => e.Organizer);
modelBuilder.Entity<TournamentViewModel>()
.HasKey(e => e.Id)
.HasRequired(e => e.Settings)
.WithRequiredDependent(e => e.Organizer);
modelBuilder.Entity<TournamentOrganizer>().Map(m => m.ToTable("Tournament"));
modelBuilder.Entity<TournamentOrganizerSetting>().Map(m => m.ToTable("Tournament"));
base.OnModelCreating(modelBuilder);
}
There doesn't seem to be a StackOverflow post with Mapping to 3 or more entities.
When I try to run it, this is the error I get:
One or more validation errors were detected during model generation:
Pro_Gaming.Infrastructure.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType.
Pro_Gaming.Infrastructure.IdentityUserRole: : EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType.
IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is based on type 'IdentityUserLogin' that has no keys defined.
IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on type 'IdentityUserRole' that has no keys defined.
This answer comes from Cole Wu from ASP.NET forums:
http://forums.asp.net/p/2093110/6043922.aspx?p=True&t=635968548324560382
The answer is the following:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Do not delete this:
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Tournament>()
.HasKey(e => e.TournamentId)
.HasRequired(e => e.Rules)
.WithRequiredPrincipal();
modelBuilder.Entity<Tournament>()
.HasKey(e => e.TournamentId)
.HasRequired(e => e.TournamentSettings)
.WithRequiredDependent();
modelBuilder.Entity<TournamentOrganizer>()
.HasKey(e => e.Id)
.HasRequired(e => e.Settings)
.WithRequiredDependent();
modelBuilder.Entity<Tournament>().ToTable("Tournament");
modelBuilder.Entity<TournamentRules>().ToTable("Tournament");
modelBuilder.Entity<TournamentSettings>().ToTable("Tournament");
modelBuilder.Entity<TournamentOrganizer>().ToTable("TournamentOrganizer");
modelBuilder.Entity<TournamentOrganizerSetting>().ToTable("TournamentOrganizer");
}
Explaining a bit:
There is no need for partial classes (I say this because there is an
example that states that you need partial classes, this is not
true):
I haven't tested this, but I used the same key for all the classes that I wanted to share the same table.
modelBuilder.Entity <= TheEntity will be the main class you want everything mapped to.
If you are using ASP.NET Identity and you are extending from IdentityDbContext (which is my case), It is very important
to include base.OnModelCreating(modelBuilder) in the OnModelCreating method, otherwise you'll be hit with Identityissues that it doesn't find the primary key for IdenittyUser.
You would then use:
modelBuilder.Entity.ToTable("MyTable")
modelBuilder.Entity.ToTable("MyTable")
modelBuilder.Entity.ToTable("MyTable")
This will map Entity1, Entity2, Entity3, etc to MyTable.
I am using Entity framework 4.1 in MVC 3 application. I have an entity where I have primary key consists of two columns ( composite key). And this is being used in another entity as foreign key. How to create the relationship ? In normal scnerios we use :
public class Category
{
public string CategoryId { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public string CategoryId { get; set; }
public virtual Category Category { get; set; }
}
but what if category has two columns key ?
You can use either fluent API:
public class Category
{
public int CategoryId1 { get; set; }
public int CategoryId2 { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public int CategoryId1 { get; set; }
public int CategoryId2 { get; set; }
public virtual Category Category { get; set; }
}
public class Context : DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Category>()
.HasKey(c => new {c.CategoryId1, c.CategoryId2});
modelBuilder.Entity<Product>()
.HasRequired(p => p.Category)
.WithMany(c => c.Products)
.HasForeignKey(p => new {p.CategoryId1, p.CategoryId2});
}
}
Or data annotations:
public class Category
{
[Key, Column(Order = 0)]
public int CategoryId2 { get; set; }
[Key, Column(Order = 1)]
public int CategoryId3 { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
[Key]
public int ProductId { get; set; }
public string Name { get; set; }
[ForeignKey("Category"), Column(Order = 0)]
public int CategoryId2 { get; set; }
[ForeignKey("Category"), Column(Order = 1)]
public int CategoryId3 { get; set; }
public virtual Category Category { get; set; }
}
I believe the easiest way is to use Data Annotation on the Navigation property like this:
[ForeignKey("CategoryId1, CategoryId2")]
public class Category
{
[Key, Column(Order = 0)]
public int CategoryId1 { get; set; }
[Key, Column(Order = 1)]
public int CategoryId2 { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
[Key]
public int ProductId { get; set; }
public string Name { get; set; }
public int CategoryId1 { get; set; }
public int CategoryId2 { get; set; }
[ForeignKey("CategoryId1, CategoryId2")]
public virtual Category Category { get; set; }
}
In .NET Core and .NET 5 < the documentation only shows Data annotations (simple key).
https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-composite-key%2Csimple-key#foreign-key
However using the example from #LadislavMrnka you will get a error message like this:
System.InvalidOperationException: There are multiple properties with
the [ForeignKey] attribute pointing to navigation ''. To define a
composite foreign key using data annotations, use the [ForeignKey]
attribute on the navigation.
Using that error message you can write the code like this:
public class Product
{
[Key]
public int ProductId { get; set; }
public string Name { get; set; }
public int CategoryId2 { get; set; }
public int CategoryId3 { get; set; }
[ForeignKey("CategoryId2,CategoryId3")]
public virtual Category Category { get; set; }
}
Fluent API (composite key) example from Microsoft:
internal class MyContext : DbContext
{
public DbSet<Car> Cars { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasKey(c => new { c.State, c.LicensePlate });
modelBuilder.Entity<RecordOfSale>()
.HasOne(s => s.Car)
.WithMany(c => c.SaleHistory)
.HasForeignKey(s => new { s.CarState, s.CarLicensePlate });
}
}
public class Car
{
public string State { get; set; }
public string LicensePlate { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public List<RecordOfSale> SaleHistory { get; set; }
}
public class RecordOfSale
{
public int RecordOfSaleId { get; set; }
public DateTime DateSold { get; set; }
public decimal Price { get; set; }
public string CarState { get; set; }
public string CarLicensePlate { get; set; }
public Car Car { get; set; }
}