How to Specify a Compound key in Entity Framework Code First

I have a quick question about setting up the mappings between [Order Details], [Products] and [Orders] in the Northwind datbase.

[Order Details] has no primary key, and looks like this

[Order Details]
OrderId (int)
ProductId (int)
...

So my question is how do I (and can I) set up my OrderDetails class to work like this?

public class OrderDetails
{
    public virtual Order Order { get; set; }
    public virtual Product Product { get; set; }
    public Decimal UnitPrice { get; set; }
    public int Quantity { get; set; }
    public Decimal Discount { get; set; }
}

My data context looks like this

public class NorthwindDb : DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }
    public DbSet<Order> Orders { get; set; }
    public DbSet<OrderDetails> OrderDetails { get; set; }
    public DbSet<Customer> Customers { get; set; }


    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new OrderDetailsConfiguration());
    }

    public static void InitializeBecauseOfThatWeirdMetaDataThingThatIDontUnderstandYet()
    {
        Database.SetInitializer<NorthwindDb>(null);
    }

}

And My OrderDetailsConfiguration (empty because I don't know what I'm doing)

public class OrderDetailsConfiguration : EntityConfiguration<OrderDetails>
{
    public OrderDetailsConfiguration()
    {
        //HasKey(x => x.Order.OrderId);
        //HasKey(x => x.Product.ProductId);
    }
}

Any hints or ideas would be great.

Answers


First you would have to explicitly put in the PKs and FKs inside OrderDetails class:

public class OrderDetails 
{        
    public int OrderID { get; set; }
    public int ProductID { get; set; }

    public virtual Order Order { get; set; }
    public virtual Product Product { get; set; }

    public Decimal UnitPrice { get; set; }
    public int Quantity { get; set; }
    public Decimal Discount { get; set; }
}

Then with the following code you can specify the PKs for OrderDetailsConfiguration class: (Please note that in Northwind database both OrderID and ProductID are PKs for OrderDetails table).

public class OrderDetailsConfiguration : EntityConfiguration<OrderDetails> 
{
    public OrderDetailsConfiguration() 
    {
        HasKey(od => new 
        {
            od.ProductID,
            od.OrderID
        });
    }
}

And also you can use RecreateDatabaseIfModelChanges strategy to force your database to be recreated every time you change the class model:

Database.SetInitializer<NorthwindDb>(
        new RecreateDatabaseIfModelChanges<NorthwindDb>());

The interesting point is that once you made these changes EF will automatically infer the FKs from OrderDetails class and create the relationships to Orders and Products table on OrderID and ProductID based on the Conventions for Code First:

Code First will infer that any property named <navigation property name><primary key property name> (i.e. ProductsProductID), <principal class name><primary key property name> (i.e. ProductProductID) or <primary key property name> (i.e. ProductID), with the same data type as the primary key, represents a foreign key for the relationship. If multiple matches are found then precedence is given in the order listed above. Foreign key detection will not be case sensitive.


Mark key fields with [Key] attribute. You will need to add [Column(Order = x)] in case of compound keys, x = 0, 1, 2, ... Numbering can start from any number https://msdn.microsoft.com/en-us/data/jj591583.aspx


Need Your Help

Empty response to API call to Facebook Graph

facebook api facebook-graph-api

I have been hammering away at this problem for the last day. I really hope someone can help me out. I would be very grateful.

Ajax modal popup inside update panel causes flickering

asp.net-ajax updatepanel modalpopupextender

I have an ajax modal popup, which is shown on click of a button in base page.