如何删除与隐藏交集表的多对多关联中的记录?

Posted

技术标签:

【中文标题】如何删除与隐藏交集表的多对多关联中的记录?【英文标题】:How to delete records in a many-to-many association with a hidden intersection table? 【发布时间】:2019-09-24 11:52:30 【问题描述】:

我们有两个表,table1 和 table2,在 SQL 中定义,具有多对多关系。

按照惯例,我们通过创建一个包含 table1 和 table2 主键的交集表 table1_table2 来实现这一点。

我们已经创建了从 table1 到 table1_table2 以及从 table2 到 table1_table2 的 1 多个 FK。

然后我们让 EF6 创建一个 EDMX,使用从数据库导入。

模型定义了两个实体,table1s 和 table2s,具有多对多关系。

即有POCO类table1包含一个ICollection table2s,class table2包含一个ICollection table1s。

如何清除连接,以便删除table1的所有实例?

这个:

using (var dbContext = new DbContext())

    dbContext.table1s.RemoveRange(dbContext.table1s);

    dbContext.SaveChanges();

抛出异常:

System.Data.SqlClient.SqlException: The DELETE statement conflicted with the REFERENCE constraint "FK_table1_table2_table1".

我首先尝试消除这种关系:

using (var dbContext = new DbContext())

    foreach (var table1 in dbContext.table1s)
        table1.table2s = null;

    dbContext.table1s.RemoveRange(dbContext.table1s);

    dbContext.SaveChanges();

我得到了同样的例外。

所以我尝试明确删除每个 table2 记录:

using (var dbContext = new DbContext())

    foreach (var table1 in dbContext.table1s)
    
        foreach (var table2 in table1.table2.ToList()
        
            table1.table2s.Remove(table2);
        
    

    dbContext.table1s.RemoveRange(dbContext.table1s);

    dbContext.SaveChanges();

这似乎行得通,但太乏味了,我很难相信这是我应该这样做的方式。

想法?

【问题讨论】:

不使用 EF 可以为自己省去很多麻烦 :) 当我们完成当前的重构时,我们将能够逐类将 EF 替换为 Dapper 或 NHibernate。但随着紧急但不重要的任务不断涌入,这将是一个漫长的过程。 它有它的位置,但很多时候你不需要它。当你使用像 dapper 这样的东西时,只要它不是超级复杂的图表,就会更加透明。 【参考方案1】:

EF

嗯,这就是使用 EF 的方式。

这并不是太多的代码,如果需要,甚至可以泛化。

如果问题是性能,那么它可能部分由

处理
    disablingautomatic change detection eagerly加载导航集合 并且可能通过直接操作entry states。

或者你可以去

不是 EF

Get(more or less reliably) table name from its DbSet(或者如果可以接受就硬编码)并用普通 SQL 删除所有有问题的行。

基本上为正确的工作使用正确的工具。

EF 通常是修改复杂对象图的不错选择,但另一方面,对于批量记录操作而言,它基本上太重了。

【讨论】:

以上是关于如何删除与隐藏交集表的多对多关联中的记录?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 SqlAlchemy 中的多对多集合中删除所有项目?

Hibernate:n-n关联关系

如何使用 Doctrine 2 创建与额外字段的多对多自引用关联?

如何在多对多表上级联删除

如何从 django 模板访问多对多“通过”表的属性?

mysql表的一对一/一对多/多对多联系