0

CastleActiveRecordを使用してテーブル内のすべての行を削除しようとしています。通常、私はこれを行います:

DB.ParseError.DeleteAll();

ただし、このテーブルには、たまたま約190万行が含まれています。上記のコマンドが行うことは、テーブルの行ごとに、次のように個別SELECTに発行することです。DELETE

SELECT page0_.Id as Id29_0_, ... FROM Indexer.Pages page0_ WHERE page0_.Id=:p0;:p0 = b03665aa-37d0-4a2d-a04c-c232ebd94dbc [Type: Guid (0)]
SELECT page0_.Id as Id29_0_, ... FROM Indexer.Pages page0_ WHERE page0_.Id=:p0;:p0 = 11cb69e3-1c6a-4ac1-908b-084dfe859639 [Type: Guid (0)]
--- 1.9 million more of these
DELETE FROM Indexer.ParseErrors WHERE Id = :p0;:p0 = b03665aa-37d0-4a2d-a04c-c232ebd94dbc [Type: Guid (0)]
DELETE FROM Indexer.ParseErrors WHERE Id = :p0;:p0 = 11cb69e3-1c6a-4ac1-908b-084dfe859639 [Type: Guid (0)]
--- 1.9 million more of these

これには時間がかかります...実際にそれを終了させる忍耐力がないので、どれくらいの時間がかかるかわかりません。

私がやりたいのは、1つのSQLステートメントを発行することです。これです:

DELETE FROM Indexer.ParseErrors;

これが私がこれまでに試したことです:

ISessionFactoryHolder holder = ActiveRecordMediator.GetSessionFactoryHolder();
ISession session = holder.CreateSession(typeof(DB.ParseError));
IDbCommand cmd = session.Connection.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "DELETE FROM Indexer.ParseErrors;";
cmd.CommandTimeout = 600;
cmd.ExecuteNonQuery();
holder.ReleaseSession(session);

これは機能しているように見えますが、モデルとActiveRecordフレームワークを完全に回避しているため、私にはハックのように見えます。さらに、これはおそらくNHibernateが持っているキャッシングではうまく機能しません。

行ごとに2つのSQLステートメントを実行せずにテーブルを削除するより公式な方法はありますか?

4

4 に答える 4

3

これだけ多くのレコードがあるテーブルの場合、行ごとにエンティティを作成してから削除することは絶対に避けてください。これには永遠に時間がかかります。

データベースに適用されていないカスケードルールがマッピングに定義されていない場合、最も簡単なのはSQLクエリを使用することです。

ActiveRecordBase<ParseError>.Execute(
    (s, i) => s.CreateSQLQuery("DELETE FROM ParseErrors").ExecuteUpdate(),
                                           null);

これにより、NHibernateキャッシュが無効になります(したがって、NHibernateの第2レベルのキャッシュでうまく機能します)が、dbで定義されていないカスケードは実行されません(あなたの場合は問題ないと思います)。データベースにないカスケードがある場合は、手動で行う必要があります。

本当にエンティティを使用して削除する場合は、少なくともStatelessSessionScopeを使用します。これにより、少なくともすべてのエンティティがセッションに追加されるのを防ぐことができます。

アップデート:

このExecute()メソッドはの保護されたメンバーでActiveRecordBase<T>あるため、クラスの外部から呼び出すには、パブリック静的メソッドでラップする必要があります。

于 2012-06-14T09:27:49.833 に答える
1

次のステートメントを使用して、nHibernateを使用してテーブルからすべてのレコードを削除できます。カスケードルールによって異なります。最初に他のテーブルをクリアする必要がある可能性があります。

session.Delete("from Indexer.ParseErrors p");

フルリンクを使用

于 2012-06-14T05:45:11.117 に答える
1

過去にこれに対処するたびに、次のようなことをしました。

session.CreateSQLQuery("DELETE FROM FOO").ExecuteUpdate();

はい、それはあらゆる種類のものをバイパスしますが、私はそれで問題があったことはありません。

Ayendeはこれについて投稿しており、バルクコピーを使用してそれを実行していますが、キャッシングに関する懸念に対処していないようです。

于 2012-06-14T15:04:56.807 に答える
0

こんにちはマイククリステンセン、

はい、それは方法です。これは良い方法ではありませんが(私は思います)、プレーンSQLよりも優れています。

session.CreateQuery(@"UPDATE " + typeof(?).FullName + " SET Property = :value")
       .SetParameter("value",valueVariable)
       .ExecuteUpdate();

NHibernateでのバッチ更新

あいさつジュイジュカ

于 2012-06-14T14:37:05.023 に答える