我将从我的表中删除数百行。使用ADO.Net代码,即使用实体框架时,Delete from table where somecolumn = somestring所花费的时间不到1秒钟,即
MyDbContext context = new MyDbContext()
context.SomeEntity.RemoveRange(context.SomeEntity.Where(i => i.somecolumn == somestring));
context.SaveChanges();花了8-10秒。
有人能解释吗或者我做错了什么。
发布于 2022-05-03 18:04:56
在这些情况下,您想要删除其中的记录(读取千或更多),最有效的方式是所谓的“批量删除”。EFCore.BulkExtensions允许这样做。如下代码所示:
var recordsToRemove = context.SomeEcontity.Where(i => i.somecolumn == somestring));
context.BulkDelete(recordsToRemove);发布于 2022-05-03 22:22:28
EF是围绕着提供映射到对象模型的关系数据而设计的。它不太适合大型批量操作。尽管如此,您还是可以通过多种方式方便一次性需求。
第一种方法是使用存根进行删除。为此,您需要确保DbContext实例对任何可能被删除的跟踪实例都是“干净的”,因此理想的情况下是将范围限定为该方法的DbContext。
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();
}现在,您可以将其简化为:
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。
context.SomEntities.RemoveRamge(stubs);
context.SaveChanges();重要的细节是,DbContext无法跟踪这些实体中的任何一个,因为这将临时将这些存根附加到DbContext。如果上下文已经使用这些ID之一跟踪实例,那么您将收到一个错误,即一个或多个具有相同ID的实体已经被跟踪。(因此,在本地范围内使用DbContext来避免这种情况)
执行此删除的另一种方法是发出直接的SQL操作。如果您的DbContext作用域为请求或比此单个操作更长,则应在处理任何当前跟踪的实例之后执行。
步骤1.如果已注入DbContext,则处理任何跟踪实例:
var trackedInstances = context.SomeEntities.Local
.Where(x => x.SomeColumn == someString);
.ToList();
if (trackedInstances.Any())
context.SomeInstances.RemoveRange(trackedInstances);这将在不触及DB的情况下检查任何跟踪实例的DbContext。我们希望删除这些实例,以避免可能将其中的任何实例标记为修改,并在稍后的SaveChanges调用中触发异常。
步骤2.构建并运行参数化原始SQL语句,以清除DB中的所有剩余行。
context.Database.ExecuteSqlCommand(@"DELETE FROM dbo.SomeEntities
WHERE SomeColumn = @someString", new SqlParameter("someString", someString));
context.SaveChanges();这里的重要细节是使用参数化查询。请执行,而不是,使用字符串中嵌入的参数执行原始SQL,因为这将为SQL注入攻击打开大门。
也就是说,不要使用类似于:
context.Database.ExecuteSqlCommand($"DELETE FROM dbo.SomeEntities
WHERE SomeColumn = '{someString}'");
// or
context.Database.ExecuteSqlCommand("DELETE FROM dbo.SomeEntities
WHERE SomeColumn = '" + someString + "'");https://stackoverflow.com/questions/72102994
复制相似问题