简体   繁体   中英

Entity Framework forming virtual collections to tables that use composite primary keys

In entity framework, how do you link a virtual collection to another table that uses composite keys? Here's two example tables:

public abstract class Table1
{
    public Guid EventId { get; set; }
    public string EventName { get; set; }

    public virtual ICollection<Table2> Table2 { get; private set; }
}

and

public abstract class Table2
{
    public Guid EventId { get; set; }
    public string DetailKey { get; set; }
    public string DetailValue { get; set; }

    public virtual Table1 Table1 { get; set; }
}

Meaning that in Table1, an event is added, and then using a one-to-many relationship, N number of rows are added to Table2. In Table1, the Guid EventId is the PK, in Table 2, the PK is composite of EventId + DetailKey , meaning that there could be N rows in Table2 related to the corresponding EventId in Table1. Table2 also has an FK of EventId to Table1's EventId.

The map file for Table1 looks like this (in part):

public override void ConfigureImp(EntityTypeBuilder<Table1> builder)
{
    base.ConfigureImp(builder);

    // Relationships            
    builder.HasMany(t => t.Table2)
          .WithOne(t => t.Table1)
          .HasForeignKey(x => new { x.EventId, x.DetailKey });
}

the map file for Table2 looks like this (in part):

public override void ConfigureImp(EntityTypeBuilder<Table2> builder)
{
    base.ConfigureImp(builder);

    // Relationships
    builder.HasOne(t => t.Table1)
         .WithMany(t => t.Table2)
         .HasForeignKey(x => x.EventId)
         .OnDelete(DeleteBehavior.Restrict)
         .IsRequired();
}

Let's add some data, say 1 row to Table1 with EventId FOO , and 5 rows to Table2, where each row in Table2 has the same EventId (to satisfy the FK) but a unique DetailKey (to satisfy the composite key). After doing this, I run a query like this:

Table1 target = db.Table1
                    .Include(x => x.Table2)
                    .SingleOrDefault(x => x.EventId.Equals("FOO"));

Upon doing this, and inspecting the contents of target (say, as a breakpoint) I would expect to see the details from Table1, as well as all 5 rows from Table2 because of the .Include . However, what I am actually getting is only a single row from Table2, whichever row comes first in the table (meaning it can change as other rows for that EventId are added to Table2.

Any thoughts as to why I'm not getting all corresponding rows from Table2 using queries such as the one shown above for target ? Thank you.

There is no need to declare the relationship twice, and the Foreign Key is just EventId.

eg


public  class Event
{
    public Guid EventId { get; set; }
    public string EventName { get; set; }

    public virtual ICollection<EventDetail> Details { get; private set; }
}
public class EventDetail
{
    public Guid EventId { get; set; }
    public string DetailKey { get; set; }
    public string DetailValue { get; set; }

    public virtual Event Event{ get; set; }
}


protected override void OnModelCreating(ModelBuilder modelBuilder)
{


     modelBuilder.Entity<EventDetail>()
         .HasOne(t => t.Event)
         .WithMany(t => t.Details)
         .HasForeignKey(x => x.EventId)
         .OnDelete(DeleteBehavior.Restrict)
         .IsRequired();

    modelBuilder.Entity<EventDetail>().HasKey(e => new { e.EventId, e.DetailKey });

    base.OnModelCreating(modelBuilder);
}

you can just add the necessary attributes and you'd should be able to avoid the methods you wrote:

public  class Event
{
    [Key]
    public virtual Guid EventId { get; set; }
    public virtual string EventName { get; set; }
    public virtual ICollection<EventDetail> Details { get; set; }
}
public class EventDetail
{
    [Key, Column(Order = 0)]
    [ForeignKey("EventId")]
    public virtual Guid EventId { get; set; }
    [Key, Column(Order = 1)]
    public virtual string DetailKey { get; set; }
    public virtual string DetailValue { get; set; }
    public virtual Event Event{ get; set; }
}

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