web-dev-qa-db-ja.com

NHibernateでのバッチ更新

NHibernateにバッチ更新コマンドはありますか?私の知る限り、そうではありません。では、この状況に対処するための最良の方法は何ですか?私は次のことをしたいと思います:

  1. データベースからオブジェクトのリスト(ユーザーのリスト、_List<User>_と呼びましょう)を取得します。
  2. それらのオブジェクトのプロパティを変更します(_Users.Foreach(User=>User.Country="Antartica"_)
  3. 各アイテムを個別に更新し直します(Users.Foreach(User=>NHibernate.Session.Update(User))。
  4. _Session.Flush_を呼び出して、データベースを更新します。

これは良いアプローチですか?これにより、コードとデータベースの間で多くのラウンドトリップが発生しますか?

どう思いますか?それとも、もっとエレガントな解決策はありますか?

24
Graviton

NHibernate 3.2バッチジョブを開始すると、データベースのラウンドトリップを最小限に抑える改善が行われます。詳細については、 HunabKuブログ をご覧ください。これがその例です-これらのバッチ更新は6回のラウンドトリップのみを実行します:

using (ISession s = OpenSession())
using (s.BeginTransaction())
{
    for (int i = 0; i < 12; i++)
    {
        var user = new User {UserName = "user-" + i};
        var group = new Group {Name = "group-" + i};
        s.Save(user);
        s.Save(group);
        user.AddMembership(group);
    }
    s.Transaction.Commit();
}
21
marisks

私はこれについてパーティーに遅れていることを知っていますが、NHibernate2.1 +でHQLを使用してこれが可能になったことを知りたいと思うかもしれません

session.CreateQuery(@"update Users set Country = 'Antarctica'")
.ExecuteUpdate();
41
MPritchard

Nhibernate構成ファイルで更新のバッチサイズを設定できます。

<property name="hibernate.adonet.batch_size">16</property>

また、そこでSession.Update(User)を呼び出す必要はありません。トランザクションをフラッシュまたはコミットするだけで、NHibernateが処理を行います。

編集:nhibernateドキュメントの関連セクションへのリンクを投稿するつもりでしたが、サイトがダウンしています- これはAyendeからの古い投稿です 件名:

ここでのNHibernate(または任意のORM)の使用が適切なアプローチであるかどうかについては、状況によって異なります。大きなテーブルのすべての行を単一の値で1回限りの更新を行う場合(すべてのユーザーを国「南極」(ちなみに国ではなく大陸です!)に設定するなど)、おそらくsql UPDATEステートメントを使用します。アプリケーションの一般的な使用法のビジネスロジックの一部として国で一度に複数のレコードを更新する場合は、ORMを使用する方が賢明な方法です。これは数によって異なります。毎回更新する行の数。

確信が持てない場合は、おそらくここで最も賢明なオプションは、NHibernateのbatch_sizeオプションを微調整して、それがどのように機能するかを確認することです。システムのパフォーマンスが許容できない場合は、コードにストレートSQLUPDATEステートメントを実装することを検討してください。

9
Steve Willcock

NHibernate 5.0以降、LINQを使用して一括操作を行うことができます。

session.Query<Cat>()
.Where(c => c.BodyWeight > 20)
.Update(c => new { BodyWeight = c.BodyWeight / 2 });

NHibernateは、単一の「更新」SQLクエリを生成します。

エンティティの更新 を参照してください

7
bN_

更新したり、フラッシュしたりする必要はありません。

IList<User> users = session.CreateQuery (...).List<User>;
users.Foreach(u=>u.Country="Antartica")
session.Transaction.Commit();

NHibernateはすべての変更のバッチを作成すると思います。

問題は、ユーザーをメモリにロードする必要があることです。問題が発生した場合でも、NHibernateを使用してネイティブSQLを使用できます。ただし、パフォーマンスの問題であることが証明されない限り、Niceソリューションを使用してください。

4

いいえ、それは良いアプローチではありません!

この種の更新には、ネイティブSQLの方が何倍も優れています。

UPDATE USERS SET COUNTRY = 'Antartica';

これを簡単にすることはできません。データベースエンジンは、一度に行よりも100倍効率的にこれを処理しますJavaコード。

1
James Anderson