329

Entity Framework を使用してテーブル内のすべての行をすばやく削除するにはどうすればよいですか?

私は現在使用しています:

var rows = from o in dataDb.Table
           select o;
foreach (var row in rows)
{
    dataDb.Table.Remove(row);
}
dataDb.SaveChanges();

ただし、実行には長い時間がかかります。

代替手段はありますか?

4

24 に答える 24

336

これをグーグルで調べて、私のようにここにたどり着いた人のために、これは現在EF5とEF6でそれを行う方法です:

context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");

コンテキストがSystem.Data.Entity.DbContext

于 2013-09-24T16:06:28.790 に答える
231

警告:以下は小さなテーブルにのみ適しています (1000 行未満と考えてください)。

これはエンティティ フレームワーク (SQL ではない) を使用して行を削除するソリューションであるため、SQL エンジン (R/DBM) 固有ではありません。

これは、テストまたは同様の状況でこれを行っていることを前提としています。また

  • データ量が少ない、または
  • 性能は申し分ない

単に呼び出す:

VotingContext.Votes.RemoveRange(VotingContext.Votes);

次のコンテキストを想定します。

public class VotingContext : DbContext
{
    public DbSet<Vote> Votes{get;set;}
    public DbSet<Poll> Polls{get;set;}
    public DbSet<Voter> Voters{get;set;}
    public DbSet<Candidacy> Candidates{get;set;}
}

コードを整理するには、次の拡張メソッドを宣言できます。

public static class EntityExtensions
{
    public static void Clear<T>(this DbSet<T> dbSet) where T : class
    {
        dbSet.RemoveRange(dbSet);
    }
}

次に、上記は次のようになります。

VotingContext.Votes.Clear();
VotingContext.Voters.Clear();
VotingContext.Candidacy.Clear();
VotingContext.Polls.Clear();
await VotingTestContext.SaveChangesAsync();

私は最近、このアプローチを使用して、テストケースの実行ごとにテストデータベースをクリーンアップしました (生成された削除コマンドの形式を確認していませんが、DB を毎回ゼロから再作成するよりも明らかに高速です)。


なぜ遅くなることがありますか?

  1. EF はすべての行を取得します (VotingContext.Votes)
  2. そして、それらの ID を使用して (正確な方法はわかりませんが、重要ではありません)、それらを削除します。

したがって、大量のデータを処理している場合は、SQL サーバー プロセスを強制終了し (すべてのメモリを消費します)、IIS プロセスについても同じことを行います。これは、EF が SQL サーバーと同じ方法ですべてのデータをキャッシュするためです。テーブルに大量のデータが含まれている場合は、これを使用しないでください。

于 2014-07-01T22:09:46.943 に答える
90

SQL のTRUNCATE TABLEコマンドを使用すると、個々の行ではなくテーブルで動作するため、最も高速になります。

dataDb.ExecuteStoreCommand("TRUNCATE TABLE [Table]");

dataDbDbContext(ではない) であると仮定するとObjectContext、それをラップして、次のようなメソッドを使用できます。

var objCtx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)dataDb).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [Table]");
于 2013-03-05T09:42:21.600 に答える
39
using (var context = new DataDb())
{
     var ctx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)context).ObjectContext;
     ctx.ExecuteStoreCommand("DELETE FROM [TableName] WHERE Name= {0}", Name);
}

また

using (var context = new DataDb())
{
     context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");
}
于 2013-03-05T09:43:17.077 に答える
21

これにより、SQLの使用が回避されます

using (var context = new MyDbContext())
{
    var itemsToDelete = context.Set<MyTable>();
    context.MyTables.RemoveRange(itemsToDelete);
    context.SaveChanges();
}
于 2015-11-16T20:49:47.280 に答える
9

特定のケースに対処しなければならなかったときに、この質問に出くわしました。「リーフ」テーブルのコンテンツを完全に更新します(FKがそれを指していません)。これには、すべての行を削除して新しい行情報を配置する必要があり、トランザクションで実行する必要があります (何らかの理由で挿入が失敗した場合、空のテーブルになってしまいたくありません)。

アプローチを試みましたpublic static void Clear<T>(this DbSet<T> dbSet)が、新しい行が挿入されません。もう 1 つの欠点は、行が 1 つずつ削除されるため、プロセス全体が遅くなることです。

TRUNCATEそのため、はるかに高速でROLLBACKableであるため、アプローチに切り替えました。また、ID をリセットします。

リポジトリ パターンを使用した例:

public class Repository<T> : IRepository<T> where T : class, new()
{
    private readonly IEfDbContext _context;

    public void BulkInsert(IEnumerable<T> entities)
    {
        _context.BulkInsert(entities);
    }

    public void Truncate()
    {
        _context.Database.ExecuteSqlCommand($"TRUNCATE TABLE {typeof(T).Name}");
    }
 }

 // usage 
 DataAccess.TheRepository.Truncate();
 var toAddBulk = new List<EnvironmentXImportingSystem>();

 // fill toAddBulk from source system
 // ...

 DataAccess.TheRepository.BulkInsert(toAddBulk);
 DataAccess.SaveChanges();

もちろん、すでに述べたように、このソリューションは外部キーによって参照されるテーブルでは使用できません (TRUNCATE は失敗します)。

于 2016-09-23T13:21:25.477 に答える
4

データベース全体をクリアしたい場合。

外部キー制約のため、テーブルがどのシーケンスで切り捨てられるかが重要です。これは、このシーケンスをブルートフォースする方法です。

    public static void ClearDatabase<T>() where T : DbContext, new()
    {
        using (var context = new T())
        {
            var tableNames = context.Database.SqlQuery<string>("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME NOT LIKE '%Migration%'").ToList();
            foreach (var tableName in tableNames)
            {
                foreach (var t in tableNames)
                {
                    try
                    {

                        if (context.Database.ExecuteSqlCommand(string.Format("TRUNCATE TABLE [{0}]", tableName)) == 1)
                            break;

                    }
                    catch (Exception ex)
                    {

                    }
                }
            }

            context.SaveChanges();
        }
    }

利用方法:

ClearDatabase<ApplicationDbContext>();

この後、DbContext を再インスタンス化することを忘れないでください。

于 2014-09-01T19:00:23.823 に答える
4

以下はSQLiteデータベース(Entity Frameworkを使用)で動作します。

context.Database.ExecuteSqlCommand("some SQL")上記のいくつかのコメントでも強調されているように、すべての db テーブルをクリアする最速の方法は を使用しているようです。ここでは、テーブルの「インデックス」カウントもリセットする方法を示します。

context.Database.ExecuteSqlCommand("delete from TableA");
context.Database.ExecuteSqlCommand("delete from sqlite_sequence where name='TableA'");//resets the autoindex

context.Database.ExecuteSqlCommand("delete from TableB");
context.Database.ExecuteSqlCommand("delete from sqlite_sequence where name='TableB'");//resets the autoindex 

context.Database.ExecuteSqlCommand("delete from TableC");
context.Database.ExecuteSqlCommand("delete from sqlite_sequence where name='TableC'");//resets the autoindex 

重要な点の 1 つは、テーブルで外部キーを使用する場合、親テーブルの前にまず子テーブルを削除する必要があるため、削除中のテーブルの順序 (階層) が重要です。そうしないと、SQLite 例外が発生する可能性があります。

ノート:var context = new YourContext()

于 2019-10-14T16:13:55.770 に答える
1

これは EF 5 で適切に機能します。

YourEntityModel myEntities = new YourEntityModel();

var objCtx = ((IObjectContextAdapter)myEntities).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [TableName]");
于 2014-09-27T16:18:53.063 に答える