1

ユーザーが渡す一連の日付に基づいて、イベント レコードをデータベースに「一括」挿入する必要があります。

私のイベント エンティティには、StartTime プロパティと StopTime プロパティがあります。Event エンティティは私のアプリケーションのコア エンティティであり、それに関連付けられた多数のコレクションとエンティティ参照があります。重い存在です。

したがって、私の元のコードでは、日付をループして次のようなことをしていました。

 Session.Save(new Event {StartTime=startdate, StopTime=endDate});

しかし、これはうまくスケーリングできず、数百の日付を挿入するときにパフォーマンスを感じました。

そのため、すべての日付を一時テーブルに挿入することを考えましたが、HQL でそれを達成する方法がわかりませんでした。

そこで、次に考えたのは、すべての日付をサブクエリとして含めて、最も近いものにすることでした。そのアプローチは次のとおりです。

var hql = "INSERT INTO Event (Code, Comment, Description, Status, StartTime, StopTime)
           SELECT ev.Code, ev.Comment, ev.Description, ev.Status, Dates.SDate, Dates.EDate
           FROM Event ev, 
                (
                    SELECT '1/2/2012 3:00:00 PM' as SDate, '1/2/2012 6:00:00 PM' as EDate
                    UNION ALL SELECT '1/3/2012 3:00:00 PM', '1/3/2012 6:00:00 PM' 
                    UNION ALL SELECT '1/4/2012 3:00:00 PM', '1/4/2012 6:00:00 PM'
                ) as Dates
           WHERE ev.Id = :sourceEventId";

Session.CreateQuery(hql).SetInt32("sourceEventId", @event.Id).ExecuteUpdate();

しかし、hql は非常にあいまいなエラー コードで失敗します。私のオンライン調査によると、hql はまだ UNION 句をサポートしていません。

現在、このアプローチを SQL として書き直し、Session.CreateSQLQuery() を介して実行すると、うまく機能します。しかし、SQLとして実行したくありません。とにかく、それはNHibernateを使用する目的に反します。

HQL (または他の NHibernate テクノロジ) を使用してこれにアプローチできる別の方法はありますか?

ここで何か助けていただければ幸いです。

アップデート

  1. これは従来の SQL Server データベースであり (sqlite で単体テストを実行しています)、すべてのエンティティが SQL の Identity 列を使用して ID を生成していることを忘れていました。そのため、バッチの試行はすべて失敗します。

  2. 以下のコメントで説明したように、ステートレス セッション アプローチも試しました。NHibernate は、遅延ロードされたすべてのエンティティを最初に保存する必要があることを教えてくれませんでした。これらのマッピングを削除することで一時的にその問題を回避しましたが、それは機能し、通常のセッションよりも高速でした. それでも、すべてのエンティティを一度に 1 つずつ挿入する必要がありました。

4

2 に答える 2

1

セッションの代わりにステートレスセッションを使用してみてください

using (var session = sessionFactory.OpenStatelessSession())
using (var tx = session.BeginTransaction())
{
for (int i = 0; i < count; i++)
{
    session.Insert(yourObjects[i]);
}
tx.Commit();
}

このリンクも役立ちます

さらに、ステートレスセッションの代わりにADO.netSqlBulkCopyを使用できます。これを確認してください

于 2012-04-04T23:20:35.980 に答える
0

これはどうですか?

var sdates = new []{ "1/2/2012 3:00:00 PM", "1/3/2012 3:00:00 PM", "1/4/2012 3:00:00 PM" };
var edates = new []{ "1/2/2012 6:00:00 PM", "1/3/2012 6:00:00 PM", "1/4/2012 6:00:00 PM" };

var hql = "INSERT INTO Event (Code, Comment, Description, Status, StartTime, StopTime)
       SELECT ev.Code, ev.Comment, ev.Description, ev.Status, :sdate, :edate
       FROM Event ev
       WHERE ev.Id = :sourceEventId";

for(var i=0;i<sdates.Length;i++)
{
     Session.CreateQuery(hql).SetInt32("sourceEventId", @event.Id)
                             .SetString("sdate", sdates[i])
                             .SetString("edate", edates[i])
                             .ExecuteUpdate();
}

おそらく、文字列の代わりにDateTimeを使用し、コードを微調整する必要がありますが、それはアイデアです。基本的に、1つではなく3つのコマンドを実行しますが、n + 1の代わりにも実行します(これがスケーリングの問題でしたよね?)

それが役に立てば幸い。

于 2012-04-05T15:43:06.960 に答える