首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >实体框架RemoveRange非常慢

实体框架RemoveRange非常慢
EN

Stack Overflow用户
提问于 2022-05-03 17:06:40
回答 2查看 239关注 0票数 0

我将从我的表中删除数百行。使用ADO.Net代码,即使用实体框架时,Delete from table where somecolumn = somestring所花费的时间不到1秒钟,即

代码语言:javascript
复制
MyDbContext context = new MyDbContext()    
context.SomeEntity.RemoveRange(context.SomeEntity.Where(i => i.somecolumn == somestring));
context.SaveChanges();

花了8-10秒。

有人能解释吗或者我做错了什么。

EN

回答 2

Stack Overflow用户

发布于 2022-05-03 18:04:56

在这些情况下,您想要删除其中的记录(读取千或更多),最有效的方式是所谓的“批量删除”。EFCore.BulkExtensions允许这样做。如下代码所示:

代码语言:javascript
复制
var recordsToRemove = context.SomeEcontity.Where(i => i.somecolumn == somestring));

context.BulkDelete(recordsToRemove);
票数 0
EN

Stack Overflow用户

发布于 2022-05-03 22:22:28

EF是围绕着提供映射到对象模型的关系数据而设计的。它不太适合大型批量操作。尽管如此,您还是可以通过多种方式方便一次性需求。

第一种方法是使用存根进行删除。为此,您需要确保DbContext实例对任何可能被删除的跟踪实例都是“干净的”,因此理想的情况下是将范围限定为该方法的DbContext。

代码语言:javascript
复制
using (var context = new SomeDbContext())
{
    var stubs = context.SomeEntities
        .Where(x => x.SomeColumn == someString)
        .Select(x => x.Id)
        .ToList()
        .Select(x => new SomeEntity { Id == x })
        .ToList();
}

现在,您可以将其简化为:

代码语言:javascript
复制
var stubs = context.SomeEntities
    .Where(x => x.SomeColumn == someString)
    .Select(x => new SomeEntity { Id == x.Id })
    .ToList();

但是,您可能希望测试它,以确保得到的SQL只是选择ID (而不是整个实体),并且context.SomeEntities.Local.Any()仍然是假的.第一个示例将确保查询加载ID,然后使用该ID构建存根实体,这使数据的“选择”尽可能高效。

从这里开始,您应该能够在未跟踪的存根上使用RemoveRange

代码语言:javascript
复制
context.SomEntities.RemoveRamge(stubs);
context.SaveChanges();

重要的细节是,DbContext无法跟踪这些实体中的任何一个,因为这将临时将这些存根附加到DbContext。如果上下文已经使用这些ID之一跟踪实例,那么您将收到一个错误,即一个或多个具有相同ID的实体已经被跟踪。(因此,在本地范围内使用DbContext来避免这种情况)

执行此删除的另一种方法是发出直接的SQL操作。如果您的DbContext作用域为请求或比此单个操作更长,则应在处理任何当前跟踪的实例之后执行。

步骤1.如果已注入DbContext,则处理任何跟踪实例:

代码语言:javascript
复制
var trackedInstances = context.SomeEntities.Local
     .Where(x => x.SomeColumn == someString);
     .ToList();

if (trackedInstances.Any())
    context.SomeInstances.RemoveRange(trackedInstances);

这将在不触及DB的情况下检查任何跟踪实例的DbContext。我们希望删除这些实例,以避免可能将其中的任何实例标记为修改,并在稍后的SaveChanges调用中触发异常。

步骤2.构建并运行参数化原始SQL语句,以清除DB中的所有剩余行。

代码语言:javascript
复制
context.Database.ExecuteSqlCommand(@"DELETE FROM dbo.SomeEntities
        WHERE SomeColumn = @someString", new SqlParameter("someString", someString));
context.SaveChanges();

这里的重要细节是使用参数化查询。请执行,而不是,使用字符串中嵌入的参数执行原始SQL,因为这将为SQL注入攻击打开大门。

也就是说,不要使用类似于:

代码语言:javascript
复制
context.Database.ExecuteSqlCommand($"DELETE FROM dbo.SomeEntities 
        WHERE SomeColumn = '{someString}'");
// or
context.Database.ExecuteSqlCommand("DELETE FROM dbo.SomeEntities 
        WHERE SomeColumn = '" + someString + "'");
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72102994

复制
相关文章

相似问题

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