C# 将虚拟集合形成到使用复合主键的表的实体框架
在实体框架中,如何将虚拟集合链接到另一个使用复合键的表?以下是两个示例表:C# 将虚拟集合形成到使用复合主键的表的实体框架,c#,sql-server,entity-framework,entity-framework-core,C#,Sql Server,Entity Framework,Entity Framework Core,在实体框架中,如何将虚拟集合链接到另一个使用复合键的表?以下是两个示例表: 公共抽象类表1 { 公共Guid事件ID{get;set;} 公共字符串EventName{get;set;} 公共虚拟ICollection表2{get;private set;} } 及 公共抽象类表2 { 公共Guid事件ID{get;set;} 公共字符串DetailKey{get;set;} 公共字符串DetailValue{get;set;} 公共虚拟表1表1{get;set;} } 这意味着在表1中,添
公共抽象类表1
{
公共Guid事件ID{get;set;}
公共字符串EventName{get;set;}
公共虚拟ICollection表2{get;private set;}
}
及
公共抽象类表2
{
公共Guid事件ID{get;set;}
公共字符串DetailKey{get;set;}
公共字符串DetailValue{get;set;}
公共虚拟表1表1{get;set;}
}
这意味着在表1中,添加一个事件,然后使用一对多关系,将N行添加到表2中。在表1中,GuidEventId
是主键,在表2中,主键由EventId+DetailKey
组合而成,这意味着表2中可能有N行与表1中相应的EventId
相关。表2的EventId的FK值也为EventId
表1的映射文件如下(部分):
public override void ConfigureImp(EntityTypeBuilder)
{
基本配置导入(生成器);
//关系
builder.HasMany(t=>t.Table2)
.带一个(t=>t.Table1)
.HasForeignKey(x=>new{x.EventId,x.DetailKey});
}
表2的映射文件如下所示(部分):
public override void ConfigureImp(EntityTypeBuilder)
{
基本配置导入(生成器);
//关系
builder.HasOne(t=>t.Table1)
.WithMany(t=>t.Table2)
.HasForeignKey(x=>x.EventId)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
}
让我们添加一些数据,比如在表1中添加一行EventIdFOO
,在表2中添加5行,其中表2中的每一行都有相同的EventId(满足FK),但有一个唯一的DetailKey(满足复合键)。完成此操作后,我运行如下查询:
Table1 target = db.Table1
.Include(x => x.Table2)
.SingleOrDefault(x => x.EventId.Equals("FOO"));
这样做之后,检查目标的内容(比如,作为断点),我希望看到表1中的详细信息,以及表2中所有5行的详细信息,因为。Include
。然而,我实际得到的只是表2中的一行,无论哪一行位于表中的第一行(这意味着它可以随着该EventId
的其他行添加到表2中而改变)
关于我为什么不使用上面所示的target
查询从表2中获取所有对应行的问题,有什么想法吗?谢谢。不需要声明两次关系,外键就是EventId
乙二醇
公开课活动
{
公共Guid事件ID{get;set;}
公共字符串EventName{get;set;}
公共虚拟ICollection详细信息{get;private set;}
}
公共类事件详细信息
{
公共Guid事件ID{get;set;}
公共字符串DetailKey{get;set;}
公共字符串DetailValue{get;set;}
公共虚拟事件事件{get;set;}
}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
modelBuilder.Entity()
.HasOne(t=>t.Event)
.有许多(t=>t.细节)
.HasForeignKey(x=>x.EventId)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
modelBuilder.Entity().HasKey(e=>new{e.EventId,e.DetailKey});
基于模型创建(modelBuilder);
}
您只需添加必要的属性,就可以避免使用您编写的方法:
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; }
}
公共类事件
{
[关键]
公共虚拟Guid事件ID{get;set;}
公共虚拟字符串EventName{get;set;}
公共虚拟ICollection详细信息{get;set;}
}
公共类事件详细信息
{
[键,列(顺序=0)]
[外键(“事件ID”)]
公共虚拟Guid事件ID{get;set;}
[键,列(顺序=1)]
公共虚拟字符串DetailKey{get;set;}
公共虚拟字符串DetailValue{get;set;}
公共虚拟事件事件{get;set;}
}
插入数据库的方法在哪里?“…获取的只是表2中的一行”你的意思是从数据库中,对吗?是的,从数据库中。为了这个示例,数据可以手动进入数据库。因此在target
示例的末尾db
是包含Table1
和Table2
模型的数据库上下文。两次声明它会导致这种类型的行为吗有连接的行又回来了?我对两边的逻辑是,除了上面的示例之外,我还可以提出这个样式请求:``Table2 target=db.Table2.Include(x=>x.Table1.SingleOrDefault(x=>x.Table1.EventId.Equals(“FOO”);```(喜欢反方向)谢谢你的回答,我只是想补充一点,我用更改过的键样式尝试了这一点,它的行为与以前相同(我从Include
中得到了一行,而不是none,也不是all),所以我想肯定还有其他原因。
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);
}
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; }
}