我需要使用Entity Framework Core从数据库中删除多行。
此代码不起作用:
foreach (var item in items)
{
myCollection.Remove(item);
}
因为我在第一个对象之后收到错误“InvalidOperationException:Collection被修改;枚举操作可能无法执行”。换句话说, .Remove 只删除一个对象。
实体框架核心没有 .RemoveRange ,所以我不知道如何执行此操作。
为了保持与各种数据库提供程序的最大兼容性,我宁愿不调用context.Database.ExecuteSqlCommand(“从physical_table中删除where ...”)。有合适的解决方案吗?谢谢!
答案 0 :(得分:12)
因为我收到错误" InvalidOperationException:Collection被修改;枚举操作可能无法执行"在第一个对象之后。换句话说,.Remove只删除一个对象。
这与EF Core无关,是的,.Remove()
只删除一个对象。但是,您正在尝试修改正在迭代的集合。有are ways to do this,但这不是一条好路。
实体框架核心没有.RemoveRange,所以我不知道如何执行此操作。
至少有几种简单的方法可以删除EF Core中的多条记录。并且,EF Core确实有RemoveRange()
方法 - 它是DbSet<TEntity>
上的方法,请参阅here in the API docs(如上面评论中所述)。
几个选项:
如果myCollection
的类型属于DbSet<TEntity>
,那么这样的简单调用就可以解决问题:
_dbContext.MyEntities.RemoveRange(myCollection);
_dbContext.SaveChanges();
如果myCollection
实际上是您查询的实体的导航属性,则可以在集合上调用.Clear()
,而不是迭代并调用.Remove()
。
var myParentEntity = _dbContext.MyParentEntities
.Include(x => x.MyChildrenEntities)
.Single(x => x.Id == id);
myParentEntity.MyChildrenEntities.Clear();
_dbContext.SaveChanges();
如上所述,您的问题中缺少很多上下文 - 应该发布更完整的代码。我只是在黑暗中做了几次刺伤,让你在EF Core上运行!
答案 1 :(得分:2)
如果你想在某个任意过滤器上删除许多项目(阅读数百或更多),最有效的方法就是所谓的&#34;批量删除&#34;。 EFCore.BulkExtensions允许这样做。查看下面的示例:
var toRemoveModels = DataAccess.ModelRepository.All
.Where(m => m.Name.StartsWith("Added model"))
.ToList();
DataAccess.ModelRepository.BulkDelete(toRemoveModels);
数据库上下文中的实际实现非常简单:
public void BulkDelete<TModel>(IList<TModel> entities) where TModel: class
{
this.BulkDelete(entities, bulkConfig: null);
}
这将生成一堆查询,但仍然比发出大量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
注意:一种更有效的方式来执行&#34;批量&#34;删除将通过提供IQueryable
来指定应该获取项目的方式,并生成类似于以下内容的DELETE
:
DELETE FROM SomeTable
WHERE Id IN (SELECT Id FROM SomeTable WHERE ...)
这更快,因为它不需要加载EF实体,也不需要创建临时表和MERGE
。
我使用了Entity Framework 6的库,但找不到EF Core的非商业库。
答案 2 :(得分:1)
您可以做这样的事情
[HttpDelete("{id}")]
public async Task<ActionResult<string>> DeleteAsset(int id)
{
_db.Assets.Remove(_db.Assets.Find(id));
await _db.SaveChangesAsync();
// Đi tìm trang table asset_image
List<AssetImage> assetImageList = _db.AssetImages.Where(x => x.AssetId == id).ToList();
foreach(AssetImage assetImageItem in assetImageList)
{
_db.AssetImages.Remove(assetImageItem);
_db.SaveChangesAsync();
}
return Ok("ok");
}
答案 3 :(得分:1)
我创建了一个库,用于通过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();