我注意到,在多到多的关系中,联合表是由ef维护的.i.e
Center
ID name
1 C1
2 C2
Facility
ID Name
1 F1
2 F2
Center_Facitliy
CenterID FacilityID
1 1
1 2
2 1
2 2如果我做了
Center = GetCenterById(2);Indcluds Center_Facilities collection
Center.Center_Facilities = new List<Center_Facility> {
new Center_Facility { FacilityID = 3 },
new Center_Facility { FacilityID = 1}
}此更新的Center_Facility表为
Center_Facitliy
CenterID FacilityID
1 1
1 2
2 1
2 3它自动删除2-2并添加2-3。有人能解释一下为什么和如何发生这种事吗?
这种情况不会发生在下面
CenterEmployee
ID Name Phone CenterID
1 E1 123 1
2 E2 123 1
3 E3 123 2(雇主只能在一个中心工作)
Center = GetCenterById(1); //Indcluds CenterEmployee collection
Center.CenterEmployee = new List<CenterEmployee> {
new CenterEmployee { Name=E5, Phone=123 },
new CenterEmployee { Name=E4, phone=123 }
}
Result
CenterEmployee
ID Name Phone CenterID
1 E1 123 null
2 E2 123 null
3 E3 123 2
4 E4 123 1
5 E5 123 1它更新了FK关系,但没有删除旧记录(1,2)。
谢谢
发布于 2019-04-11 06:36:48
在更新Center.Center_Facilities时,如下所示:
Center.Center_Facilities = new List<Center_Facility> {
new Center_Facility { FacilityID = 3 },
new Center_Facility { FacilityID = 1}
}这意味着您要用一个新的Center_Facilities集合替换Center中现有的Center_Facilities (已经加载到上下文中)集合,这就是为什么要删除以前的集合,并添加新的集合。这是实体框架的预期行为,否则,如果新集合包含数据库中已经存在的一组Center_Facility,那么它将抛出重复的关键异常。
此外,现在认为您不想替换,而是要添加到现有的Center_Facilities集合中,那么您必须这样做:
Center.Center_Facilities.AddRange(new List<Center_Facility> {
new Center_Facility { FacilityID = 3 },
new Center_Facility { FacilityID = 1}
})在这种情况下,您必须确保新添加的集合不包含数据库中已经存在的任何Center_Facility集。
希望现在对你来说是清楚的。
发布于 2019-04-11 07:36:01
删除2、2和2、3的原因是因为您刚刚告诉dbContext,Center 2只有Ids 1和3的中心设施。
没错,关系数据库管理系统使用一个单独的表实现了一个多到多的关系:连接表。通常,连接表只有连接项的Ids。由于组合CenterId、FacilityId是唯一的,这种组合通常用作主键,这使得查询速度非常快。
如果首先在实体框架代码中设计多对多的关系,则不必提及连接表:
class Center
{
public int Id {get; set;}
...
// every Center offers zero or more facilities (many-to-many)
public virtual ICollection<Factility> Facilities {get; set;}
}
class Facility
{
public int Id {get; set;}
...
// every Facility is offered at zero or more Centers (many-to-many)
public virtual ICollection<Center> Centers {get; set;}
}
class MyDbContext : DbContext
{
public DbSet<Center> Centers {get; set;}
public DbSet<Facility> Facilities {get; set;}
}请注意,没有提到连接表!
在实体框架中,表的列由非虚拟属性表示。虚拟属性表示表之间的关系。
由于具有双面虚拟ICollection,实体框架可以检测到您设计了一个多到多的关系,并将自动为您创建一个合适的连接表,而不需要属性或fluent API。
但是如何在没有连接表的情况下进行查询?
不要使用连接表,而是使用ICollections:
给我(几个)英国中心的(几个属性)他们陈旧的设施:
var result = dbContext.Centers
.Where(center => center.CountryCode == "UK")
.Select(center => new
{
// select only the properties that you plan to use
Id = center.Id,
Name = center.Name,
...
ObsoleteFacilities = center.Facilities
.Where(facility => facility.Obsolete)
.Select(facility => new
{
// again, only the properties you plan to use
Id = facility.Id,
...
})
.ToList(),
});实体框架知道您的多到多,并且足够聪明地理解为此需要一个(组-)与连接表的连接。
现在,如果您已经获取了Center 2和设施3,那么很容易将它们连接起来,而不必担心它们之间是否已经存在关系:
var center2 = dbContext.Centers.Find(2);
var facility3 = dbContext.Facilities.Find(3);
// TODO: check if really found
// connect them:
center2.Facilities.Add(facility3);
// add a new facility:
center.Facilities.Add(new Facility() {...});
dbContext.SaveChanges();或者,您可以将该中心添加到该设施中:
facility3.Centers.Add(center2);
dbContext.Facilities.Add(new Facility()
{
...
Centers = new Center[] {center2},
});除了这个非常直观的优点之外,更好的一点是,您不必担心center2和facility3之间是否已经存在关系。
缺点是,您必须获取完整的中心和设施。通常,比起添加和更新,查询数据的频率要高得多,而且更改关系通常是在(相对缓慢的)用户交互之后进行的,因此我怀疑这是否会成为一个问题。
但是,如果您真的想要添加关系,而不必先获取中心和设施,则可以添加包含连接表的DbSet。
public DbSet<CenterFacility> CenterFacilities {get; set;}为了增加这种关系:
dbContext.CenterFunctions.Add(new CenterFacility()
{
CenterId = 2,
FacilityId = 3,
});但你确定没有这种关系吗?你得先把它拿来。你确定这个关系不是别人在你的抓取和你的加法之间添加的吗?
你看,这么多的问题,只是不值得你自己处理接合表!
https://stackoverflow.com/questions/55625908
复制相似问题