【问题标题】:Entity Framework forming virtual collections to tables that use composite primary keys实体框架对使用复合主键的表形成虚拟集合
【发布时间】:2021-08-14 04:40:07
【问题描述】:

在实体框架中,如何将一个虚拟集合链接到另一个使用复合键的表?这是两个示例表:

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

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

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; }
}

意思是在Table1中添加一个事件,然后使用一对多的关系,向Table2添加N行。在表1中,GuidEventId是PK,在表2中,PK是EventId + DetailKey的合成,这意味着表2中可能有N行与表1中对应的EventId相关。 Table2 对 Table1 的 EventId 也有一个 FK 为 EventId

Table1 的地图文件如下所示(部分):

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 });
}

Table2 的地图文件如下所示(部分):

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();
}

让我们添加一些数据,比如向 Table1 添加 1 行 EventId FOO,向 Table2 添加 5 行,其中 Table2 中的每一行具有相同的 EventId(以满足 FK)但唯一的 DetailKey(以满足复合键)。完成此操作后,我运行如下查询:

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

执行此操作并检查target 的内容(例如,作为断点)我希望看到来自Table1 的详细信息,以及来自Table2 的所有5 行,因为.Include。但是,我实际上得到的只是 Table2 中的一行,无论哪一行在表中先出现(这意味着它可以随着 EventId 的其他行添加到 Table2 中而改变。

有什么想法为什么我没有使用上面为target 显示的查询从 Table2 中获取所有相应的行?谢谢。

【问题讨论】:

  • 您用来插入数据库的方法在哪里? “...获取只是 Table2 中的一行”你的意思是从数据库对吗?
  • 是的,来自数据库。就示例而言,数据可以手动到达数据库。所以在target 示例中,最后db 是包含Table1Table2 模型的数据库上下文。

标签: c# sql-server entity-framework entity-framework-core


【解决方案1】:

关系不需要声明两次,外键就是EventId。

例如


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);
}

【讨论】:

  • 是否会两次声明它会导致这种类型的行为,其中只有一个连接的行返回?我对双方的逻辑是,除了上面的示例之外,我还可以提出这种样式请求:``` Table2 target = db.Table2 .Include(x => x.Table1) .SingleOrDefault(x => x.Table1.EventId .Equals("FOO")); ```(喜欢往反方向走)
  • 感谢您的回答,只是想补充一点,我尝试使用更改的键样式进行此操作,并且它具有与以前相同的行为(我从Include 得到一行,而不是没有,而不是全部),所以我认为肯定有其他事情发生。
【解决方案2】:

你可以只添加必要的属性,你应该能够避免你写的方法:

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; }
}

【讨论】:

    猜你喜欢
    • 2015-12-25
    • 1970-01-01
    • 2011-11-05
    • 1970-01-01
    • 2016-06-08
    • 1970-01-01
    • 1970-01-01
    • 2012-03-26
    • 1970-01-01
    相关资源
    最近更新 更多