Entity Frameworkを使用してテーブル内のすべての行をすばやく削除する方法を教えてください。
私は現在使用しています:
var rows = from o in dataDb.Table
select o;
foreach (var row in rows)
{
dataDb.Table.Remove(row);
}
dataDb.SaveChanges();
ただし、実行に時間がかかります。
代替案はありますか?
これをグーグルしていて、私のようにここで終わった人たちにとって、これはあなたが現在EF5とEF6でやっている方法です:
context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");
コンテキストがSystem.Data.Entity.DbContext
であると仮定
警告:以下は小さなテーブルにのみ適しています(< 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を最初から再作成するよりも明らかに高速です)。
なぜ遅くなるのですか?
大量のデータを扱う場合は、SQLサーバープロセスを強制終了し(すべてのメモリを消費します)、IISプロセスでも同じことが行われます。EFはすべてのデータをキャッシュするのと同じ方法でキャッシュするためです。 SQLサーバー。テーブルに大量のデータが含まれている場合は、これを使用しないでください。
SQLの TRUNCATE TABLE
コマンドを使用すると、個々の行ではなく表に対して処理が行われるため、最も高速になります。
dataDb.ExecuteStoreCommand("TRUNCATE TABLE [Table]");
dataDb
がDbContext
(ObjectContext
ではない)であると仮定すると、それをラップして次のようなメソッドを使用することができます。
var objCtx = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)dataDb).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [Table]");
var all = from c in dataDb.Table select c;
dataDb.Table.RemoveRange(all);
dataDb.SaveChanges();
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]");
}
これはSQLの使用を避けます
using (var context = new MyDbContext())
{
var itemsToDelete = context.Set<MyTable>();
context.MyTables.RemoveRange(itemsToDelete);
context.SaveChanges();
}
あなたはForeachなしでそれをすることができます
dataDB.Table.RemoveRange(dataDB.Table);
dataDB.SaveChanges();
これですべての行が削除されます
私が特定のケースに対処しなければならなかったとき、私はこの質問に出くわしました:「リーフ」テーブルの内容の完全な更新(それを指す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は失敗します)。
もし
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");
}
データベース全体を消去したい場合。
外部キー制約のため、テーブルがどの順序で切り捨てられるかが重要です。これはこのシーケンスを強引にする方法です。
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を再インスタンス化することを忘れないでください。
var data = (from n in db.users select n);
db.users.RemoveRange(data);
db.SaveChanges();
これはEF 5では正しく機能します。
YourEntityModel myEntities = new YourEntityModel();
var objCtx = ((IObjectContextAdapter)myEntities).ObjectContext;
objCtx.ExecuteStoreCommand("TRUNCATE TABLE [TableName]");
すべてのレコードを削除してください。 "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;
}