简体   繁体   中英

How do I map an inherited table with a composite key using Entity Framework code-first?

I have two classes, something like this:

public class Customer {
    public string Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class CustomerChange : Customer {
    public DateTime ChangedAtUtc { get; set; }
}

I'm trying to map these to a database schema using Entity Framework code-first. The schema should look like this:

+-------------+
| Customer    |
+-------------|
| * Id        |
|   FirstName |
|   LastName  |
+-------------+
       |
       |
      /|\
  +----------------+
  | CustomerChange |
  +----------------+
  | * Id           |
  | * ChangedAtUtc |
  |   FirstName    |
  |   LastName     |
  +----------------+

So the Customer table shows you the LATEST state of every customer, and every time the customer changes, we UPDATE the Customer table and INSERT a row into the CustomerChange table. CustomerChange gives you a complete history of the state of that Customer record over time - note that CustomerChanges should be considered immutable in this model.

I've tried putting a [Key] attribute on both the Customer.Id and the CustomerChange.ChangedAtUtc properties, but that didn't work. I've tried explicitly overriding OnModelCreating:

modelBuilder.Entity<CustomerChange>().Map(m => {
    m.MapInheritedProperties();
    m.ToTable("CustomerChanges");
}).HasKey(change => new { change.Id, change.ChangedAtUtc });

but I cannot get EF to create the CustomerChanges table with the composite key (Id, ChangedAtUtc)

(Yes, in this example, I'm relying on the id+timestamp being unique. This is fine.)

How should I decorate/override the various Entity Framework bits to create this table correctly?

I think this should work. Defince Customer class as:

//Customer class
public class Customer
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    //Relationships
    public virtual ICollection<CustomerChange> CustomerChanges { get; set; }
}

//Mapping details for Customer
public class CustomerMap : EntityTypeConfiguration<Customer>
{
    public CustomerMap()
    {
        this.HasKey(c => c.Id);
    }
}

Defince CustomerChange as:

//CustomerChange class
public class CustomerChange
{
    public int Id { get; set; }
    public DateTime ChangeDate { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    //Relationships
    public virtual Customer Customer { get; set; }
}

//Mapping details for CustomerChange class
public class CustomerChangeMap : EntityTypeConfiguration<CustomerChange>
{
    public CustomerChangeMap()
    {
        this.HasKey(c => new { c.Id, c.ChangeDate });

        //Relationship mappings
        this.HasRequired(cm => cm.Customer)
            .WithMany(c => c.CustomerChanges)
            .HasForeignKey(cm => cm.Id);
    }
}

Then add mapping details at OnModelCreating

public override void OnModelCreating()
{
    this.Configurations.Add(new CustomerMap());
    this.Configurations.Add(new CustomerChangeMap());
}

I hope it will work for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM