Entity Framework CodeFirst many to many relationship with additional information

21,275

Solution 1

In such case you must model your entities this way:

public class Contract
{
   public virtual string ContractId { get; set; }
   public virtual ICollection<ContractPart> ContractParts { get; set; }
}

public class Part
{
   public virtual string PartId { get;set; }
   public virtual ICollection<ContractPart> ContractParts { get; set; }
}

public class ContractPart
{ 
   public virtual string  ContractId { get; set; }
   public virtual string PartId { get; set; }
   public virtual Contract Contract { get; set; }
   public virtual Part Part { get; set; }
   public virtual string Date { get; set; } //additional info
   public virtual decimal Price { get; set; } //additional info
}

In derived context you must define:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
   modelBuilder.Entity<ContractPart>()
               .HasKey(cp => new { cp.ContractId, cp.PartId });

   modelBuilder.Entity<Contract>()
               .HasMany(c => c.ContractParts)
               .WithRequired()
               .HasForeignKey(cp => cp.ContractId);

   modelBuilder.Entity<Part>()
               .HasMany(p => p.ContractParts)
               .WithRequired()
               .HasForeignKey(cp => cp.PartId);  
}

Solution 2

Perhaps a better way to do is this answer? Create code first, many to many, with additional fields in association table

It doesn't require fluent APIs and also sets up the PK on join table.

Share:
21,275

Related videos on Youtube

Attilah
Author by

Attilah

Updated on July 09, 2022

Comments

  • Attilah
    Attilah almost 2 years

    I have the following model :

    class Contract
    {
       string ContractID{get;set;}
       ICollection<Part> Parts{get;set;}
    }
    
    class Part
    {
       string PartID{get;set;}
       ICollection<Contract> Contracts{get;set;}
    }
    

    the problem is that the relationship between Part and Contract also contains the following additional information :

    class ContractParts
    { 
       Contract{get;set;}
       Part{get;set;}
       Date{get;set;} //additional info
       Price{get;set;} //additional info
    }
    

    How would I write the Entity Context for this ?

  • Mark Good
    Mark Good about 13 years
    Thanks for the good answer! It helped. I knew about making the navigation properties virtual, but why did you make the scalar properties virtual?
  • Ladislav Mrnka
    Ladislav Mrnka about 13 years
    It is used for improving change tracking performance when using attached entities.
  • Mark Good
    Mark Good about 13 years
    Is this true for properties that you don't intend to change (such as the primary key)?
  • Ladislav Mrnka
    Ladislav Mrnka about 13 years
    @Mark: Good question. I never thought about this. I'm not sure if all properties must be virtual to allow this.
  • one.beat.consumer
    one.beat.consumer over 11 years
    @LadislavMrnka: What do you think? stackoverflow.com/questions/13260306/…
  • aruno
    aruno almost 11 years
    What I like about this link is that are some good examples of how to actually Perform updates once your model is in place
  • aruno
    aruno almost 11 years
    @ladislavmrna can you explain why you needed to use fluent? Isn't this all convention based ? Similar answer doesn't use fluent : stackoverflow.com/a/7053393/16940
  • Ladislav Mrnka
    Ladislav Mrnka almost 11 years
    @Simon_Weaver: Relation configurations should not be necessary - default convention should handle them but configuration of composite key is necessary. If you don't use it you need to use attributes to tell EF about primary key of ContractPart class.
  • granadaCoder
    granadaCoder over 10 years
    Is there a way to get a surrogate key on the ContractPart ( ContractPartSurrogateKey ) ?