user2024449
user2024449

Reputation:

Many-to-many relationship in Entity Framework Core when one entity has composite primary key

I have the following classes:

public class InvoiceLine
{
    public Guid Id { get; set; }

    public int LineNumber { get; set; }    

    public List<ProductCode> ProductCodes { get; set; }    
}

public class ProductCode
{
    public string Category { get; set; }
    public string Value { get; set; }
}

In the case of ProductCode the Category and the Value are together the primary key.

I set this up in the DbContext:

modelBuilder.Entity<ProductCode>()
            .HasKey(pc => new { pc.Category, pc.Value });

One InvoiceLine can have many product codes but a product code can be used for various InvoiceLines.

In EF Core I have to create a join entity with the ids and entitites:

public class InvoiceLineProductCode
{
    public Guid InvoiceLineId { get; set; }
    public InvoiceLine InvoiceLine { get; set; }
    public ProductCode ProductCode { get; set; }            
}

How can I set the ProductCodeId?

Upvotes: 2

Views: 3221

Answers (1)

Ivan Stoev
Ivan Stoev

Reputation: 205849

Adding composite FK is similar to adding single column FK.

Start by adding the PK column(s) of the referenced entity:

public class InvoiceLineProductCode
{
    public Guid InvoiceLineId { get; set; }
    public InvoiceLine InvoiceLine { get; set; }
    public string ProductCodeCategory { get; set; } // <--
    public string ProductCodeValue { get; set; } // <--
    public ProductCode ProductCode { get; set; }
}

Then define the composite join entity PK as usual:

modelBuilder.Entity<InvoiceLineProductCode>()
    .HasKey(e => new { e.InvoiceLineId, e.ProductCodeCategory, e.ProductCodeValue });

Also don't forget to change the Invoice collection navigation property type:

public class InvoiceLine
{
    public Guid Id { get; set; }
    public int LineNumber { get; set; }    
    public List<InvoiceLineProductCode> ProductCodes { get; set; } // <--
}

and since the names match EF Core conventions, you are done. In cases they don't, the full configuration of the relationship ProductCode -> InvoiceLineProductCode would be like this:

modelBuilder.Entity<InvoiceLineProductCode>()
    .HasOne(e => e.ProductCode)
    .WithMany()
    .HasForeignKey(e => new { e.ProductCodeCategory, e.ProductCodeValue })
    .IsRequired()
    .OnDelete(DeleteBehavior.Cascade);

Upvotes: 4

Related Questions