LINQ toEntitiesでの一括削除


82

LINQまたはLINQ-to-Entitiesの特定のクエリに一致するオブジェクトの束を一括削除する方法はありますか?私が見つけることができる唯一の参照は古く、削除したいすべてのオブジェクトを繰り返して手動で削除するのはばかげているようです。

回答:



53

しばらく前に、Entity Frameworkでの一括更新(1つのコマンド)をカバーする4部構成のブログシリーズ(第1部、第2部第3部、および第4部)を作成しました。

そのシリーズの焦点は更新でしたが、削除を行うために関連する原則を確実に使用できます。

したがって、次のようなものを書くことができるはずです。

var query = from c in ctx.Customers
            where c.SalesPerson.Email == "..."
            select c;

query.Delete();

あなたがする必要があるのはDelete()拡張メソッドを実装することです。方法のヒントについては、投稿シリーズを参照してください...

お役に立てれば


17
誰かがそれを持っているなら、ここにこれのためのコードサンプルがあるといいでしょう!
jocull 2012年


1
github.com/loresoft/EntityFramework.ExtendedEF5に依存していることに注意してください。Nugetパッケージマネージャーコンソールを使用してインストールすると、EF5のインストールを求められることなくインストールされます
Paul Zahra

1
それは実際には役に立ちません-私はDeleteコマンドの実用的な例を見たいのであり、本番コードで自分自身を実装する方法を「推測」せず、おそらく何かを台無しにします。-1
nuzzolilo 2013

27
うーん...だから、質問への答えは、聴衆に特定の答えを提示するのではなく、4つのブログ投稿にリダイレクトすることです。
DeepSpace101 2013

41
    using (var context = new DatabaseEntities())
    {
        // delete existing records
        context.ExecuteStoreCommand("DELETE FROM YOURTABLE WHERE CustomerID = {0}", customerId);
    }

3
+ 1-EFを使用してSQLコードを実行する方法のコード例を見るのはうれしい
Carlos P

2
ストアドプロシージャを作成する以外は、これがおそらくこれを行う唯一の方法であると思いますが、これは不正行為のように感じます=)。これを使用しているので、EFの奇妙な笑いを回避するために他のいくつかの場所で使用したいと思います-複雑な左結合やグループバイなど..... :)
Losbear 2012

+!... DBを使用する場合、必要なツールはドライバーであることがわかります。EFは単なるハンマーです。
gbjbaanb 2013

2
わずかな欠点:開発環境から切断されたデータベースコマンドがあります。強く型付けされていないため、このSQLの列のデータベースへの変更は、Visual Studioでは強調表示さません
Ian

7

私がここで見ている答えはLinqtoSqlです

DeleteAllOnSubmitは、System.Data.LinqおよびITableの一部であり、Linq toSqlです。

これは、EntityFrameworkでは実行できません。

とは言っても、まだ解決策はありませんが、解決策があれば投稿します。


5

EF6を使用していて、削除のために行SQLクエリを実行したい場合:

using (var context = new DatabaseEntities())
{
    // delete existing records
    context.Database.ExecuteSqlCommand("DELETE FROM YOURTABLE WHERE CustomerID = @id", idParameter);
}

1
これはEF5で機能しましたが、パラメータに@ p0を使用する必要がありました。素晴らしいのは、生成されたSQLでタイプセーフなパラメータチェックを提供することです。したがって、EF5では、これは機能します。context.Database.ExecuteSqlCommand( "DELETE FROM YOURTABLE WHERE CustomerID = @ p0"、idParameter); 次のパラメータなどの\ @ p1 ...
Nathan Prather 2014年

3

RemoveRangeはEF6で導入され、オブジェクトのリストを削除できます。超簡単。

var origins= (from po in db.PermitOrigins where po.PermitID == thisPermit.PermitID select po).ToList();
db.PermitOrigins.RemoveRange(origins);
db.SaveChanges();

1
このコードスニペットは質問を解決する可能性がありますが、説明を含めると、投稿の品質を向上させるのに役立ちます。あなたは将来読者のために質問に答えていることを忘れないでください、そしてそれらの人々はあなたのコード提案の理由を知らないかもしれません。
DimaSan 2017

2

クエリ内のすべてのレコードを削除するデータコンテキストのDeleteAllOnSubmitメソッドを知っています。多くのオブジェクトが削除されているため、基礎となる最適化が必要です。でもわかりません。


3
実際には、実行されている最適化はありません。生成されたSQLは、クエリに一致するすべてのオブジェクトを列挙し、それらを手動で繰り返して削除します。確かに、反復はコードではなくDBで行われますが、コンテンツを削除するためだけに結果セットを不必要に構築しています。これは、単純な「DELETE FROM table WHERE foo = bar」よりもはるかに悪い結果です。結果セットはなく、テーブルを1回だけカバーします。
ベンジャミンポラック

2

それがどれほど効率的かはわかりませんが、次のようなことを試すことができます。

// deletes all "People" with the name "Joe"
var mypeople = from p in myDataContext.People
               where p.Name == "Joe";
               select p;
myDataContext.People.DeleteAllOnSubmit(mypeople);
myDataContext.SubmitChanges();

1
それでも、クエリに一致するすべての要素を反復処理することになります。コードではなく、DB上でこれを行うだけです。より効率的ですが、それでも理想的なソリューションにはほど遠いです。
ベンジャミンポラック

3
それで、私がそれを行うと考えることができる他の唯一の方法は、myDataContext.ExecuteCommand( "DELETE ...");を実行することです。理想からは程遠いですが、うまくいくでしょう。
スコットアンダーソン

1

削除を実行するストアドプロシージャを記述して、LINQから呼び出すことができます。セットベースの削除は全体的に高速である可能性がありますが、影響するレコードが多すぎると、ロックの問題が発生する可能性があり、レコードのセットをループするハイブリッドが必要になる場合があります(一度に2000の場合、サイズはデータベースの設計によって異なりますが、2000はセットベースのdelteが非常に長くかかり、テーブルの他の使用に影響を与えていることがわかった場合の開始場所)。


1

Entity Frameworkを介したデータの削除は、DeleteObjectメソッドの使用に依存しています。このメソッドは、削除するエンティティクラスのEntityCollectionまたは派生ObjectContextで呼び出すことができます。簡単な例を次に示します。

NorthwindEntities db = new NorthwindEntities();

IEnumerable<Order_Detail> ods = from o in db.Order_Details
                                where o.OrderID == 12345                                    
                                select o;

foreach (Order_Detail od in ods) 
    db.Order_Details.DeleteObject(od);

db.SaveChanges();

ただし、これは「一括削除」ではありません。
nuzzolilo 2013

1

この例では、削除するレコードを取得し、それらを1つずつ結果セットに添付してから、削除するように要求します。次に、1つの保存変更があります。

    using (BillingDB db = new BillingDB())
    {
      var recordsToDelete = (from i in db.sales_order_item
                  where i.sales_order_id == shoppingCartId
                  select i).ToList<sales_order_item>();

      if(recordsToDelete.Count > 0)
      {
        foreach (var deleteSalesOrderItem in recordsToDelete)
        {                  
            db.sales_order_item.Attach(deleteSalesOrderItem);
            db.sales_order_item.Remove(deleteSalesOrderItem);                  
        }
        db.SaveChanges();
      } 
    }

1
 context.Entity.Where(p => p.col== id)
               .ToList().ForEach(p => db.Entity.DeleteObject(p));

これらは、EFを使用してDBからレコードを削除するための最速の方法です


0

私は次のようなことをします:

var recordsToDelete = (from c in db.Candidates_T where c.MyField == null select c).ToList<Candidates_T>();
if(recordsToDelete.Count > 0)
{
    foreach(var record in recordsToDelete)
    {
        db.Candidate_T.DeleteObject(record);
        db.SaveChanges();
    }
}   

Entity Frameworkはエンティティで動作するため、ループなしでそれを行う方法はないと思います。ほとんどの場合、これらはオブジェクトのコレクションを意味します。


あなたもあなたがしたことを共有することができます。ありがとう。
G Jeny Ramirez

@G JenyRamirez私のソリューションを追加しました。
Demodave 2015

2
@GJennyRamirezもあなたの例では、変更を複数回保存しています。これは、foreachループの外側に引き出して、1回実行できると思います
Demodave 2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.