首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >自动添加/删除联合表中的行

自动添加/删除联合表中的行
EN

Stack Overflow用户
提问于 2019-04-11 06:22:14
回答 2查看 54关注 0票数 1

我注意到,在多到多的关系中,联合表是由ef维护的.i.e

代码语言:javascript
复制
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

如果我做了

代码语言:javascript
复制
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表为

代码语言:javascript
复制
Center_Facitliy
CenterID    FacilityID
1             1
1             2
2             1
2             3

它自动删除2-2并添加2-3。有人能解释一下为什么和如何发生这种事吗?

这种情况不会发生在下面

代码语言:javascript
复制
CenterEmployee
ID   Name     Phone    CenterID
1    E1       123       1
2    E2       123       1
3    E3       123       2

(雇主只能在一个中心工作)

代码语言:javascript
复制
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)。

谢谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-04-11 06:36:48

在更新Center.Center_Facilities时,如下所示:

代码语言:javascript
复制
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集合中,那么您必须这样做:

代码语言:javascript
复制
Center.Center_Facilities.AddRange(new List<Center_Facility> { 
                                   new Center_Facility { FacilityID = 3 }, 
                                   new Center_Facility { FacilityID = 1}    
                                })

在这种情况下,您必须确保新添加的集合不包含数据库中已经存在的任何Center_Facility集。

希望现在对你来说是清楚的。

票数 2
EN

Stack Overflow用户

发布于 2019-04-11 07:36:01

删除2、2和2、3的原因是因为您刚刚告诉dbContext,Center 2只有Ids 1和3的中心设施。

没错,关系数据库管理系统使用一个单独的表实现了一个多到多的关系:连接表。通常,连接表只有连接项的Ids。由于组合CenterId、FacilityId是唯一的,这种组合通常用作主键,这使得查询速度非常快。

如果首先在实体框架代码中设计多对多的关系,则不必提及连接表:

代码语言:javascript
复制
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:

给我(几个)英国中心的(几个属性)他们陈旧的设施:

代码语言:javascript
复制
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,那么很容易将它们连接起来,而不必担心它们之间是否已经存在关系:

代码语言:javascript
复制
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();

或者,您可以将该中心添加到该设施中:

代码语言:javascript
复制
facility3.Centers.Add(center2);
dbContext.Facilities.Add(new Facility()
{
    ...
    Centers = new Center[] {center2},
});

除了这个非常直观的优点之外,更好的一点是,您不必担心center2和facility3之间是否已经存在关系。

缺点是,您必须获取完整的中心和设施。通常,比起添加和更新,查询数据的频率要高得多,而且更改关系通常是在(相对缓慢的)用户交互之后进行的,因此我怀疑这是否会成为一个问题。

但是,如果您真的想要添加关系,而不必先获取中心和设施,则可以添加包含连接表的DbSet。

代码语言:javascript
复制
public DbSet<CenterFacility> CenterFacilities {get; set;}

为了增加这种关系:

代码语言:javascript
复制
dbContext.CenterFunctions.Add(new CenterFacility()
{
    CenterId = 2,
    FacilityId = 3,
});

但你确定没有这种关系吗?你得先把它拿来。你确定这个关系不是别人在你的抓取和你的加法之间添加的吗?

你看,这么多的问题,只是不值得你自己处理接合表!

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55625908

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档