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.