使用 RemoveRange() 批量删除行

Posted

技术标签:

【中文标题】使用 RemoveRange() 批量删除行【英文标题】:Bulk deleting rows with RemoveRange() 【发布时间】:2014-04-05 02:32:13 【问题描述】:

我正在尝试从表中删除多行。

在常规 SQL Server 中,这很简单:

DELETE FROM Table
WHERE
    Table.Column = 'SomeRandomValue'
    AND Table.Column2 = 'AnotherRandomValue'

在 Entity Framework 6 中,他们引入了RemoveRange() 方法。 但是,当我使用它时,Entity Framework 不是使用我提供的 where 子句删除行,而是查询数据库以获取与 where 子句匹配的所有行,并使用它们的主键将它们一一删除。

这是目前 EntityFramework 的限制吗? 还是我用RemoveRange() 错了?

以下是我使用RemoveRange()的方式:

db.Tables.RemoveRange(
    db.Tables
        .Where(_ => _.Column == 'SomeRandomValue'
            && _.Column2 == 'AnotherRandomValue')
);

【问题讨论】:

Tables 是您存储库的名称吗? EntityFramework.Extended 具有batch delete 看看这个:***.com/questions/2519866/… @CristiPufu & @paqogomez:是的,我正在检查 EntityFramework.Extended。不幸的是,MS 构建了RemoveRange() 函数,但它仍然循环。 我相信 RemoveRange 是一个社区贡献,它比自己循环遍历一堆实体要快一些,但它仍然一个一个地删除它们。 EF 中没有内置对批量删除的支持(除了运行自己的 SQL) 【参考方案1】:

我认为我们在这里达到了 EF 的限制。 有时您只需要使用ExecuteSqlCommand 即可保持性能。

【讨论】:

【参考方案2】:

您正在寻找的是一个批量删除库,它可以在不加载实体的情况下从 LINQ 查询中删除数据库中的多条记录。

存在多个支持此功能的库。

您可以在此处找到该列表:Entity Framework Batch Delete Library

免责声明:我是项目的所有者Entity Framework Plus

// using Z.EntityFramework.Plus; // Don't forget to include this.

// DELETE directly in SQL (without loading entities)
db.Tables.Where(_ => _.Column == 'SomeRandomValue'
                     && _.Column2 == 'AnotherRandomValue')
         .Delete();

// DELETE using a BatchSize      
db.Tables.Where(_ => _.Column == 'SomeRandomValue'
                     && _.Column2 == 'AnotherRandomValue')
         .Delete(x => x.BatchSize = 1000);

维基:EF+ Batch Delete

【讨论】:

【参考方案3】:

有点破,试试

db.Tables.RemoveRange(
    db.Tables
        .Where(_ => _.Column == 'SomeRandomValue'
            && _.Column2 == 'AnotherRandomeValue').AsEnumerable().ToList()
);
db.SaveChanges();

【讨论】:

对不起,我仍然得到与此代码相同的结果。 Entity Framework 执行内部查询,然后遍历每一行并删除它们。【参考方案4】:
var db1 =  db.Tables
        .Where(_ => _.Column == 'SomeRandomValue'
            && _.Column2 == 'AnotherRandomeValue').AsEnumerable().ToList();
db.Tables.RemoveRange(db1);
db.SaveChanges();

使用变量存储可移动列表并将其传递给 RemoveRange()。

我通常这样做,这就是工作。 希望这也适用于您的情况。

【讨论】:

对不起,我仍然得到与此代码相同的结果。 Entity Framework 执行内部查询,然后遍历每一行并删除它们。 如果您的表有外键,请在模型中使用 [Foreign] 属性指定并使用虚拟【参考方案5】:

退一步思考。您真的要从数据库中下载记录以删除它们吗?仅仅因为你能做到这一点并不是一个好主意。

也许您可以考虑使用存储过程从数据库中删除项目? EF 也允许这样做...

【讨论】:

我同意这种情况下的存储过程是更好的解决方案。但是,我也认为这是 EF 的不足之处。删除符合特定条件的行是基本的 CRUD。存储过程更好地做到这一点的事实违背了使用 ORM 的意义。 有一种被称为“orm 阻抗不匹配”的东西,简而言之,它说明数据库是为 - 速度或 CRUD 操作 - 磁盘上的有效大小 - 引用完整性而不仅仅是为了保持重新启动后可用的数据或使跨系统边界共享数据成为可能。【参考方案6】:

我自己正在处理这个问题,并且同意 Adi - 只需使用 sql。

我正在清理日志表中的旧行,而 EF RemoveRange 花了 3 分钟的时间来做同样的事情,这在 3 秒内完成:

DELETE FROM LogEntries WHERE DATEDIFF(day, GETDATE(), Date) < -6

日期是包含日期的列的名称。为了使其正确,当然可以使用一个参数,如下所示:

  context.Database.ExecuteSqlCommand
      ("DELETE FROM  LogEntries WHERE DATEDIFF(day, GETDATE(), Date) < @DaysOld", new System.Data.SqlClient.SqlParameter(
                        "DaysOld", - Settings.DaysToKeepDBLogEntries));

请注意,我的案例涉及很多行。当我开始项目并且没有大量数据时,RemoveRange 工作正常。

【讨论】:

【参考方案7】:

我也遇到过这个问题,这是我使用 LoreSoft 的一个名为 entityframework.extended 的库的解决方法(您可以从 nuget 包管理器中获得它):

1.您首先向他们查询您的列表。 2.然后使用.Delete(),它是来自.extended库的函数。

var removeList = db.table.Where(_ => _.Column == 'SomeRandomValue'&& _.Column2 == 'AnotherRandomValue')        
removeList .Delete();

注意:根据Entity Framework EF extended,截至撰写本文时,此 entityframework.extended 已弃用。因此,可能需要考虑实体框架加库。虽然我没有在 plus 扩展上进行测试,但我可以确认它可以使用 .extended 库工作。

【讨论】:

你应该解释一下.Delete()来自外部库,不是实体框架的一部分 @csamleong,这个问题中有多个 cmets 和答案指向 Entity Framework Extended。我的问题的目的是看看是否有一种普通的 EF 方法可以做到这一点。根据我得到的答案,没有。虽然我刚刚放弃了这个问题并继续前进,但很高兴看到这个问题仍然困扰着很多人。希望 EF 能尽快解决问题,或者将 EF 扩展应用到自己的产品中。

以上是关于使用 RemoveRange() 批量删除行的主要内容,如果未能解决你的问题,请参考以下文章

Window/Linux命令行操作Redis之最最全的基本操作

linux批量删除进程

批量DOS删除指定文件命令

EF Core中高效批量删除更新数据的Zack.EFCore.Batch发布三个新特性

怎么使用SQL语句批量删除多个表的相同字段

Python批量删除mysql中千万级大量数据