简体   繁体   English

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

[英]How do I delete multiple rows in Entity Framework Core?

I need to delete multiple rows from a database using Entity Framework Core.我需要使用 Entity Framework Core 从数据库中删除多行。

This code does NOT work:此代码不起作用:

foreach (var item in items)
{
    myCollection.Remove(item);
}

because I get an error "InvalidOperationException: Collection was modified; enumeration operation may not execute" after the first object.因为我在第一个对象之后收到错误“InvalidOperationException:集合已修改;枚举操作可能无法执行”。 In other words, .Remove removes only one object.换句话说, .Remove只删除一个对象。

Entity Framework Core does NOT have .RemoveRange , so I have no idea how to perform this operation. Entity Framework Core 没有.RemoveRange ,所以我不知道如何执行此操作。

In order to preserve maximum compatibility with the various database providers, I would prefer NOT to call context.Database.ExecuteSqlCommand("delete from physical_table where...").为了保持与各种数据库提供程序的最大兼容性,我不希望调用 context.Database.ExecuteSqlCommand("delete from physical_table where...")。 Is there a suitable solution?有合适的解决方案吗? Thanks!谢谢!

because I get an error "InvalidOperationException: Collection was modified; enumeration operation may not execute" after the first object.因为我在第一个对象之后收到错误“InvalidOperationException:集合已修改;枚举操作可能无法执行”。 In other words, .Remove removes only one object.换句话说, .Remove 只删除一个对象。

This has nothing to do with EF Core, and, yes, .Remove() only removes one object.这与 EF Core 无关,是的, .Remove()仅删除一个对象。 However, you are attempting to modify a collection that you are iterating through.但是,您正在尝试修改正在迭代的集合。 There are ways to do this , but this isn't a good route to go.很多方法可以做到这一点,但这不是一条好的路线。

Entity Framework Core does NOT have .RemoveRange, so I have no idea how to perform this operation. Entity Framework Core 没有 .RemoveRange,所以我不知道如何执行此操作。

There are definitely at least a couple simple ways to delete multiple records in EF Core.肯定至少有几种简单的方法可以删除 EF Core 中的多个记录。 And, EF Core does have a RemoveRange() method - it's a method on DbSet<TEntity> , see here in the API docs (as stated in the comment above).而且,EF Core 确实有一个RemoveRange()方法 - 它是DbSet<TEntity>上的一个方法,请参阅API 文档中的此处(如上面的评论中所述)。

A couple options:几个选项:

  1. If myCollection is of a type that belongs to a DbSet<TEntity> , a simple call such as this will do the trick:如果myCollection是属于DbSet<TEntity> ,那么像这样的简单调用就可以解决问题:

     _dbContext.MyEntities.RemoveRange(myCollection); _dbContext.SaveChanges();
  2. If myCollection is actually a navigation property off of an entity that you queried, you can call .Clear() on the collection instead of iterating and calling .Remove() .如果myCollection实际上是您查询的实体的导航属性,您可以在集合上调用.Clear()而不是迭代和调用.Remove()

     var myParentEntity = _dbContext.MyParentEntities .Include(x => x.MyChildrenEntities) .Single(x => x.Id == id); myParentEntity.MyChildrenEntities.Clear(); _dbContext.SaveChanges();

As also commented above, there's a lot of context missing on your question - more complete code should be posted.正如上面所评论的,您的问题缺少很多上下文 - 应该发布更完整的代码。 I'm just taking a couple stabs in the dark to get you up and running with EF Core!我只是在黑暗中尝试了几次,让您开始使用 EF Core!

If you want to remove many items (read hundreds or more) on some arbitrary filter, the most efficient way would be a so called "bulk delete".如果您想在某个任意过滤器上删除许多项目(读取数百个或更多),最有效的方法是所谓的“批量删除”。 EFCore.BulkExtensions allows that. EFCore.BulkExtensions允许这样做。 Check an example below:检查下面的示例:

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

where the actual implementation within the database context is as simple as:其中数据库上下文中的实际实现非常简单:

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

This will generate a bunch of queries, but will still be more efficient than issuing lots of DELETE statements:这将生成一堆查询,但仍然比发出大量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

Note: a more efficient way of performing a "bulk" delete would be by providing an IQueryable which specifies the way items should be fetched and generates a DELETE similar to the following one:注意:执行“批量”删除的一种更有效的方法是提供一个IQueryable ,它指定应获取项目的方式并生成类似于以下内容的DELETE

DELETE FROM SomeTable
WHERE Id IN (SELECT Id FROM SomeTable WHERE ...)

This is faster because it does not require to load EF entities, nor create temporary table and MERGE against it.这更快,因为它不需要加载 EF 实体,也不需要针对它创建临时表和MERGE

I have used a library for Entity Framework 6, but could not find a non-commercial one for EF Core.我使用了 Entity Framework 6 的库,但找不到 EF Core 的非商业库。

You can do something like this你可以做这样的事情

[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");
}

I have created a library to batch delete or update records with a round trip on EF Core 5.我创建了一个库,用于在 EF Core 5 上通过往返来批量删除或更新记录。

Sample code as follows:示例代码如下:

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();

Github repository Github 存储库

Report of the library 图书馆报告

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM