27

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 ?

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
Attilah
  • 17,632
  • 38
  • 139
  • 202

2 Answers2

41

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);  
}
Diego
  • 18,035
  • 5
  • 62
  • 66
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • Thanks for the good answer! It helped. I knew about making the navigation properties virtual, but why did you make the scalar properties virtual? – Mark Good Apr 03 '11 at 17:34
  • 1
    It is used for improving change tracking performance when using attached entities. – Ladislav Mrnka Apr 03 '11 at 17:46
  • Is this true for properties that you don't intend to change (such as the primary key)? – Mark Good Apr 03 '11 at 19:58
  • @Mark: Good question. I never thought about this. I'm not sure if all properties must be virtual to allow this. – Ladislav Mrnka Apr 03 '11 at 20:03
  • @LadislavMrnka: What do you think? http://stackoverflow.com/questions/13260306/entity-framework-5-code-first-cyclical-relationship-issues – one.beat.consumer Nov 06 '12 at 22:22
  • @ladislavmrna can you explain why you needed to use fluent? Isn't this all convention based ? Similar answer doesn't use fluent : http://stackoverflow.com/a/7053393/16940 – Simon_Weaver May 09 '13 at 09:11
  • 2
    @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. – Ladislav Mrnka May 09 '13 at 09:37
  • Is there a way to get a surrogate key on the ContractPart ( ContractPartSurrogateKey ) ? – granadaCoder Dec 03 '13 at 20:29
5

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.

Community
  • 1
  • 1
Shital Shah
  • 63,284
  • 17
  • 238
  • 185
  • What I like about this link is that are some good examples of how to actually Perform updates once your model is in place – Simon_Weaver May 09 '13 at 08:52