Entity Frameworkコアで複数行を削除するにはどうすればよいですか?

entity-framework-core

質問

Entity Framework Coreを使用してデータベースから複数の行を削除する必要があります。

このコードは機能しません:

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

最初のオブジェクトの後に "InvalidOperationException:コレクションが変更された;列挙操作が実行されない"というエラーが発生するためです。つまり、 .Removeは1つのオブジェクトのみを削除します。

Entity Framework Coreには.RemoveRangeがありません。 したがって 、この操作の実行方法はわかりません。

さまざまなデータベースプロバイダとの最大限の互換性を維持するために、私はcontext.Database.ExecuteSqlCommand( "physical_tableからの削除...")を呼び出さないことをお勧めします。適切な解決策はありますか?ありがとう!

受け入れられた回答

最初のオブジェクトの後に "InvalidOperationException:コレクションが変更された;列挙操作が実行されない"というエラーが発生するためです。つまり、.Removeは1つのオブジェクトのみを削除します。

これはEF Coreとは何の関係もなく、はい.Remove()は1つのオブジェクトだけを削除します。ただし、反復処理中のコレクションを変更しようとしています。これを行う方法はありますが、これは良いルートではありません。

Entity Framework Coreには.RemoveRangeがありません。したがって、この操作の実行方法はわかりません。

EFコアで複数のレコードを削除するには、少なくとも2つの簡単な方法があります。また、EF CoreにはRemoveRange()メソッドがあります。これはDbSet<TEntity>メソッドです(上記のコメントに記載されているAPIドキュメントを参照)。

カップルオプション:

  1. myCollectionDbSet<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コアで動かすために暗闇の中でいくつかのスタブを取っています!


人気のある回答

いくつかの任意のフィルタで多くのアイテム(数百またはそれ以上を読む)を削除したい場合、最も効率的な方法はいわゆる "一括削除"です。 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

注: "一括"削除を実行するより効率的な方法は、アイテムをフェッチする方法を指定し、次のようなDELETEを生成するIQueryableを提供することです。

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

これは、EFエンティティをロードする必要もなく、一時テーブルとMERGE作成する必要もないため、高速です。

私はEntity Framework 6用のライブラリを使用しましたが、EFコア用の非営利のものは見つかりませんでした。



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ