如何刪除Entity Framework Core中的多個行?

entity-framework-core

我需要使用Entity Framework Core從數據庫中刪除多行。

此代碼不起作用:

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

因為我收到錯誤“InvalidOperationException:Collection被修改;枚舉操作可能無法執行”在第一個對象之後。換句話說, .Remove只刪除一個對象。

實體框架核心沒有.RemoveRange ,所以我不知道如何執行此操作。

為了保持與各種數據庫提供程序的最大兼容性,我寧願不調用context.Database.ExecuteSqlCommand(“從physical_table中刪除where ...”)。有合適的解決方案嗎?謝謝!

一般承認的答案

因為我收到錯誤“InvalidOperationException:Collection被修改;枚舉操作可能無法執行”在第一個對象之後。換句話說,.Remove只刪除一個對象。

這與EF Core無關,是的, .Remove()只刪除一個對象。但是,您正在嘗試修改正在迭代的集合。有辦法做到這一點 ,但這不是一個好的途徑。

實體框架核心沒有.RemoveRange,所以我不知道如何執行此操作。

肯定至少有幾種簡單的方法可以刪除EF Core中的多個記錄。並且,EF Core確實有一個RemoveRange()方法 - 它是DbSet<TEntity>上的一個方法,請參閱API文檔 (如上面的註釋中所述)。

幾個選項:

  1. 如果myCollection是屬於DbSet<TEntity> ,那麼這樣的簡單調用就可以解決這個問題:

    _dbContext.MyEntities.RemoveRange(myCollection);
    _dbContext.SaveChanges();
    
  2. 如果myCollection實際上是您查詢的實體的導航屬性,則可以在集合上調用.Clear()而不是迭代並調用.Remove()

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

如上所述,您的問題中缺少很多上下文 - 應該發布更完整的代碼。我只是在黑暗中採取一些刺激讓你和EF Core一起運行!


熱門答案

如果你想刪除某些任意過濾器上的許多項目(讀取數百或更多),最有效的方法就是所謂的“批量刪除”。 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

注意:執行“批量”刪除的更有效方法是提供IQueryable ,該IQueryable指定應該獲取項目的方式並生成類似於以下內容的DELETE

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

這樣更快,因為它不需要加載EF實體,也不需要創建臨時表和MERGE

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



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因