web-dev-qa-db-ja.com

エンティティフレームワーク。テーブル内のすべての行を削除

Entity Frameworkを使用してテーブル内のすべての行をすばやく削除する方法を教えてください。

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

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

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

代替案はありますか?

241
Zhenia

これをグーグルしていて、私のようにここで終わった人たちにとって、これはあなたが現在EF5とEF6でやっている方法です:

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

コンテキストがSystem.Data.Entity.DbContextであると仮定

265
Ron Sijm

警告:以下は小さなテーブルにのみ適しています(< 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サーバー。テーブルに大量のデータが含まれている場合は、これを使用しないでください。

184
Ahmed Alejo

SQLの TRUNCATE TABLE コマンドを使用すると、個々の行ではなく表に対して処理が行われるため、最も高速になります。

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

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

var objCtx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)dataDb).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [Table]");
82
Rudi Visser
var all = from c in dataDb.Table select c;
dataDb.Table.RemoveRange(all);
dataDb.SaveChanges();
37
user3328890
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]");
}
31
Manish Mishra

これはSQLの使用を避けます

using (var context = new MyDbContext())
{
    var itemsToDelete = context.Set<MyTable>();
    context.MyTables.RemoveRange(itemsToDelete);
    context.SaveChanges();
}
13
Rob Sedgwick

あなたはForeachなしでそれをすることができます

dataDB.Table.RemoveRange(dataDB.Table);
dataDB.SaveChanges();

これですべての行が削除されます

11
Omid Farvid

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

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

それで、私はTRUNCATEアプローチに切り替えました、なぜならそれははるかに速くそしてそれはまた ROLLBACKable だからです。それはまたアイデンティティをリセットします。

リポジトリパターンの使用例

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は失敗します)。

8
Alexei

もし

      using(var db = new MyDbContext())
            {
               await db.Database.ExecuteSqlCommandAsync(@"TRUNCATE TABLE MyTable"););
            }

原因

テーブル 'MyTable'はFOREIGN KEY制約によって参照されているため、切り捨てることはできません。

私はこれを使う:

      using(var db = new MyDbContext())
               {
                   await db.Database.ExecuteSqlCommandAsync(@"DELETE FROM MyTable WHERE ID != -1");
               }
4
Zakos

データベース全体を消去したい場合。

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

    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を再インスタンス化することを忘れないでください。

4
Kristian Nissen
var data = (from n in db.users select n);
db.users.RemoveRange(data);
db.SaveChanges();
3
DBB

これはEF 5では正しく機能します。

YourEntityModel myEntities = new YourEntityModel();

var objCtx = ((IObjectContextAdapter)myEntities).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [TableName]");
1
Hekmat

すべてのレコードを削除してください。 "truncate"のようにプライマリインデックスをリセットしないでください。

/// <summary>
/// SET - DELETE all record by table - no truncate - return deleted records
/// </summary>
public static int setListDelAllMYTABLE()
{
    // INIT
    int retObj = 0;
    using (MYDBEntities ctx = new MYDBEntities())
    {
        // GET - all record
        var tempAllRecord = ctx.MYTABLE.ToList();
        // RESET
        ctx.MYTABLE.RemoveRange(tempAllRecord);
        // SET - final save
        retObj += ctx.SaveChanges();
    }
    // RET
    return retObj;
}
0
Roberto Mutti