5

NHibernateでマップされていないレガシーエンティティでNHibernateを使用しようとしています。これは、レガシーエンティティをNHibernateにマップされたエンティティに接続しようとしたときに外部キー例外を受け取らないように、NHibernateデータをデータベースに手動でフラッシュする必要があることを意味します。

これがトランザクション内で発生し、その後ロールバックする必要がある場合、問題が発生します。NHibernateからフラッシュされたデータはロールバックされません。

これについて私にできることはありますか?

アップデート

これを行う方法にまだ興味があります-与えられた答えのどちらも問題に対処しているとは思いません。Flush()を呼び出す必要があります。問題は、フラッシュされたデータをどのようにロールバックするかです。

4

3 に答える 3

4

これを確認してください:フラッシュ/コミットなしでクエリの実行を強制する

私は同じ問題を抱えているようで、フラッシュしてからロールバックしましたが、一部のデータはデータベースに残りました。ただし、私のコードには、ロールバックできないコミットを呼び出す部分がいくつかありました。承認された回答のコード スニペットをトランザクション、フラッシュ、ロールバック、およびコミットの適切な使用法と見なし、このパターンを拡張できることを考慮してください...

単一の作業単位で (つまり、Web アプリケーション内の要求を単一の作業単位と見なし、その要求で発生するすべてのことは、onEndRequest がコミットされる単一のトランザクションに存在します):

  1. _sessionFactory.OpenSession()_session.BeginTransaction()_session.CommitTransaction()および を1 回だけ呼び出します_session.CloseSession()

  2. _session.Flush()and_session.RollBackTransaction()は何度でも呼び出すことができますが、コミット時に Flush() が自動的に呼び出されます。クエリを作成し、フェッチされたデータが古くならないようにする必要がある場合は、Flush を呼び出すことができます。

  3. コミット トランザクションがコミットされると、その後のすべての操作はそのトランザクションでは実行されないことに注意してください。代わりに、NHibernate は内部で必要なトランザクションを作成します ( http://www.nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions )。その時点で、一貫性とおそらく論理的整合性を追跡する問題がすでに発生しています。

  4. 作業単位の途中で commit を呼び出す必要がある場合は、明示的に管理できるように、その時点で新しいトランザクションを作成することを強くお勧めします。

  5. さらに良いのは、ネストされたトランザクションを試してみることです。これにより、部分的なコミットが可能になると言われています。「ルート」トランザクションをロールバックすると、すべての変更が元に戻されます。.NET と SQL Server のこの機能を実際にテストしたことはありませんが、データベース自体のネストされたトランザクションには多くの要望があり、ADO.NET がこの機能をどのように計測するのか正確にはわかりません。

ポイント 1 から 4 は、NHibernate の 1.2 以降のすべてのバージョンでテストされています。

于 2011-04-11T18:39:38.030 に答える
3

フォーマットのために、ここでtolism7の回答を更新することを許可します。

  1. 使用usingして、transaction.Dispose()を忘れてください-usingブロックの最後でtransaction自動的に削除されます。Dispose
  2. throw-スタックトレースを破棄することを意味するため、exをスローしないでください(「.NETFrameworkがこのステートメントを実行すると、現在の関数より上のすべてのスタック情報が破棄されます」と記載されているこの投稿を参照してください)。throw ex;

public void CommitChanges()
{
    using (var transaction = Session.BeginTransaction())  // <-- open scope
        try
        {
            // do something
            transaction.Commit();
        }
        catch (HibernateException)
        {
            transaction.Rollback();
            _session.Close();
            _session.Dispose();

            throw;  // <-- this way the stacktrace stays intact!
        }
}

このコードのVB.NETバージョンはここにあります。

于 2010-07-13T12:14:47.530 に答える
2

NHibernate でトランザクションを使用する場合は、Session.Flush() の使用を避け、代わりに内部で session.flush() を呼び出す transaction.Commit() を使用してください。

Commit() 中にエラーが発生し、トランザクションをロールバックする必要がある場合は、次のように対処できます。

public static void CommitChanges()
{
    ITransaction transaction = Session.BeginTransaction();

    try
    {
        transaction.Commit();
    }
    catch (HibernateException ex)
    {
        transaction.Rollback();
        //close and dispose session here
        throw ex;
    }
    finally
    {
        transaction.Dispose();
    }
}

現在、flush() の手動呼び出しまたは commit() の呼び出しが成功した場合、NHibernate メカニズムを使用してトランザクションをロールバックする方法はありません。特に transaction.Commit() コマンドを呼び出すと、NHibernate によって作成された AdoTransaction は Commit() が終了した直後に破棄されるため、ロールバックするためにアクセスすることはできません。

上記のコード サンプルを使用すると、コミット中に発生したエラーをキャッチして、既に開始されているトランザクションをロールバックできます。

上記のサンプルで transaction.Commit() を呼び出す代わりに、私のテストで session.Flush() を呼び出します。トランザクションは決してコミットされないため、データはデータベースに保存されません。

コードがどのように見えるかはわかりませんが、上記のコードサンプルが示すように、パターンで呼び出している場合、Session.Flush() の代わりに transaction.commit() を使用すると、目的を達成する方法が得られるはずです。欲しいです。

于 2009-11-19T11:45:41.523 に答える