如何删除Entity Framework Core中的多个行?

Gio*_*rgo 15 c# entity-framework-core

我需要使用Entity Framework Core从数据库中删除多行.

此代码不起作用:

foreach (var item in items)
{
    myCollection.Remove(item);
}
Run Code Online (Sandbox Code Playgroud)

因为我收到错误"InvalidOperationException:Collection被修改;枚举操作可能无法执行"在第一个对象之后.换句话说,.Remove只删除一个对象.

实体框架核心没有.RemoveRange,所以我不知道如何执行此操作.

为了保持与各种数据库提供程序的最大兼容性,我宁愿不调用context.Database.ExecuteSqlCommand("从physical_table中删除where ...").有合适的解决方案吗?谢谢!

ste*_*lla 18

因为我收到错误"InvalidOperationException:Collection被修改;枚举操作可能无法执行"在第一个对象之后.换句话说,.Remove只删除一个对象.

这与EF Core无关,是的,.Remove()只删除一个对象.但是,您正在尝试修改正在迭代的集合.有办法做到这一点,但这不是一条好路.

实体框架核心没有.RemoveRange,所以我不知道如何执行此操作.

肯定至少有几种简单的方法可以删除EF Core中的多个记录.并且,EF Core确实有一个RemoveRange()方法 - 它是一个方法DbSet<TEntity>,请参阅API文档(如上面的注释中所述).

几个选项:

  1. 如果myCollection是属于a的类型,那么DbSet<TEntity>这样的简单调用就可以解决问题:

    _dbContext.MyEntities.RemoveRange(myCollection);
    _dbContext.SaveChanges();
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果myCollection实际上是您查询的实体的导航属性,则可以调用.Clear()集合而不是迭代和调用.Remove().

    var myParentEntity = _dbContext.MyParentEntities
                             .Include(x => x.MyChildrenEntities)
                             .Single(x => x.Id == id);
    myParentEntity.MyChildrenEntities.Clear();
    _dbContext.SaveChanges();
    
    Run Code Online (Sandbox Code Playgroud)

如上所述,您的问题中缺少很多上下文 - 应该发布更完整的代码.我只是在黑暗中采取一些刺激让你启动和运行EF核心!

  • @Kinetic-执行此操作时,您是否还记得它是否在其子对象为.include()`d的父实体上?我还没有这样做,但是,如果您在未跟踪的孩子列表上执行`.Clear()`,则可能什么都不做。 (2认同)

Ale*_*xei 9

如果您想在某个任意过滤器上删除许多项目(读取数百个或更多),最有效的方法是所谓的“批量删除”。EFCore.BulkExtensions允许这样做。检查下面的示例:

var toRemoveModels = DataAccess.ModelRepository.All
    .Where(m => m.Name.StartsWith("Added model"))
    .ToList();
DataAccess.ModelRepository.BulkDelete(toRemoveModels);
Run Code Online (Sandbox Code Playgroud)

其中数据库上下文中的实际实现非常简单:

public void BulkDelete<TModel>(IList<TModel> entities) where TModel: class
{
    this.BulkDelete(entities, bulkConfig: null);
}
Run Code Online (Sandbox Code Playgroud)

这将生成一堆查询,但仍然比发出大量DELETE语句更有效:

SELECT [m].[Id], [m].[MakeId], [m].[Name], [m].[PriceInEur]
FROM [Model] AS [m]
WHERE [m].[Name] LIKE N'Added model' + N'%' AND (LEFT([m].[Name], LEN(N'Added model')) = N'Added model')
go
SELECT columnproperty(object_id('dbo.[Model]'),'Id','IsIdentity');
go
SELECT TOP 0 T.[Id] INTO dbo.[ModelTemp208f3efb] FROM dbo.[Model] AS T LEFT JOIN dbo.[Model] AS Source ON 1 = 0;
go
select @@trancount; SET FMTONLY ON select * from dbo.[ModelTemp208f3efb] SET FMTONLY OFF exec ..sp_tablecollations_100 N'[dbo].[ModelTemp208f3efb]'
go
insert bulk dbo.[ModelTemp208f3efb] ([Id] Int)
go
MERGE dbo.[Model] WITH (HOLDLOCK) AS T USING dbo.[ModelTemp208f3efb] AS S ON T.[Id] = S.[Id] WHEN MATCHED THEN DELETE;
go
DROP TABLE dbo.[ModelTemp208f3efb]
go
Run Code Online (Sandbox Code Playgroud)

注意:执行“批量”删除的一种更有效的方法是提供IQueryable指定应获取项目的方式并生成DELETE类似于以下内容的方式:

DELETE FROM SomeTable
WHERE Id IN (SELECT Id FROM SomeTable WHERE ...)
Run Code Online (Sandbox Code Playgroud)

这更快,因为它不需要加载 EF 实体,也不需要MERGE针对它创建临时表。

我使用了 Entity Framework 6 的库,但找不到 EF Core 的非商业库。

  • 可能值得注意的是 EFCore.BulkExtensions 不支持 MySQL。https://github.com/borisdj/EFCore.BulkExtensions/issues/71 (3认同)
  • 当核心支持批量操作时,为什么要使用外部依赖项 (2认同)
  • @johnny5您能否更清楚地说明如何在 ef core 中不依赖外部依赖项的情况下进行批量删除? (2认同)
  • 只是为了展示如何通过查询 `context.Items.Where(a =&gt; a.ItemId &gt; 500).BatchDeleteAsync();` 进行删除 (2认同)

小智 6

我创建了一个库,用于在 EF Core 5 上进行往返批量删除或更新记录。

示例代码如下:

await ctx.DeleteRangeAsync(b => b.Price > n || b.AuthorName == "zack yang");

await ctx.BatchUpdate()
.Set(b => b.Price, b => b.Price + 3)
.Set(b=>b.AuthorName,b=>b.Title.Substring(3,2)+b.AuthorName.ToUpper())
.Set(b => b.PubTime, b => DateTime.Now)
.Where(b => b.Id > n || b.AuthorName.StartsWith("Zack"))
.ExecuteAsync();
Run Code Online (Sandbox Code Playgroud)

Github 存储库

图书馆的报告