I'm getting to grips with EF4 code first, and liking it so far. But I'm having trouble mapping an entity to a table with a composite primary key.
The configuration I've tried looks like this:
public SubscriptionUserConfiguration() { Property(u => u.SubscriptionID).IsIdentity(); Property(u => u.UserName).IsIdentity(); }
Which throws this exception: Unable to infer a key for entity type 'SubscriptionUser'.
What am I missing?
In order to use composite keys, Entity Framework requires you to define an order for the key properties. You can do this by using the Column annotation to specify an order. The order value is relative (rather than index based) so any values can be used. For example, 100 and 200 would be acceptable in place of 1 and 2.
Entity Framework Core supports composite keys - primary key values generated from two or more fields in the database. Composite keys are not covered by conventions or data annotation attributes. The only way to configure composite keys is to use the HasKey method.
You could also use
HasKey(u => new { u.SubscriptionID, u.UserName });
Edit:
One limitation I have found is that the following do not work:
public ProjectAssignmentConfiguration() { HasKey(u => u.Employee.EmployeeId); HasKey(u => u.Project.ProjectId); }
or
public ProjectAssignmentConfiguration() { HasKey(u => new { u.Employee.EmployeeId, u.Project.ProjectId }); }
So how do you set up an entity where the join table has a primary key that is composed of foreign keys?
I will try to explain it step by step, using the following Entity
public class Account { public int AccountId1 { get; set; } public int AccountId2 { get; set; } public string Description { get; set; } }
Create a class derived from the EntityTypeConfiguaration<TEntity>
Object to override the conventions
class AccountEntityTypeConfiguration : EntityTypeConfiguration<Account> { public AccountEntityTypeConfiguration() { // The Key // The description of the HasKey Method says // A lambda expression representing the property to be used as the primary key. // If the primary key is made up of multiple properties then specify an anonymous type including the properties. // Example C#: k => new { k.Id1, k.Id2 } // Example VB: Function(k) New From { k.Id1, k.Id2 } this.HasKey(k => new { k.AccountId1, k.AccountId2 } ); // The Key // Maybe the key properties are not sequenced and you want to override the conventions this.Property(p => p.AccountId1).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None); this.Property(p => p.AccountId2).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None); this.Property(p => p.Description).IsRequired(); // This property will be required this.ToTable("Account"); // Map the entity to the table Account on the database } }
When create the class derived from the DbContext
Object, override OnModelCreating
Method and add a new AccountEntityTypeConfiguration
object to the Configurations of the model Builder.
public class MyModelAccount : DbContext { public DbSet<Account> Accounts { get; set;} protected override void OnModelCreating(DbModelBuilder modelBuilder) { // Add a new AccountEntityTypeConfiguration object to the configuration of the model, that will be applied once the model is created. modelBuilder.Configurations.Add(new AccountEntityTypeConfiguration()); } }
Hope it helps you!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With