2

次のようなコードがあります。

public void Foo(int userId)
{
    try {
        using (var tran = NHibernateSession.Current.BeginTransaction())
        {
            var user = _userRepository.Get(userId);
            user.Address = "some new fake user address";
            _userRepository.Save(user);
            Validate();
            tran.Commit();
        }
    }
    catch (Exception) {
        logger.Error("log error and don't throw")
    }
}

private void Validate()
{
    throw new Exception();
}

そして、検証が正しく行われたかどうかを単体テストしたいと思います。テストには nunit と SQLLite データベースを使用します。テストコードは次のとおりです。

protected override void When()
{
    base.When();
    ownerOfFooMethod.Foo(1);
    Session.Flush();
    Session.Clear();
}

[Test]
public void FooTest()
{
    var fakeUser = userRepository.GetUserById(1);
    fakeUser.Address.ShouldNotEqual("some new fake user address");
}

私のテストは失敗します。
デバッグ中に、例外がスローされ、コミットが呼び出されていないことがわかります。しかし、ロールバックされることを期待していましたが、ユーザーの Address プロパティにはまだ「新しい偽のユーザーアドレス」があります。
nhibernate プロファイラーを見ていると、begin transaction ステートメントが表示されますが、その後にコミットもロールバックもありません。
さらに、try-catch ブロックを配置して、catch で明示的に Rollback を実行しても、テストは失敗します。
テスト環境に問題があると思いますが、すべて問題ないようです。

何か案は?

編集: 重要な try-catch ブロックを追加しました (最初はコードを単純化しすぎました)。

4

1 に答える 1

3

NH が変更をデータベースにフラッシュする前に例外が発生し、オブジェクトを削除/クリアせずにそのセッションを使用し続け、後で何らかの理由でフラッシュが発生した場合、オブジェクトがまだダーティであるため、変更は引き続き保持されます。 NHibernateによると。トランザクションをロールバックするときは、この種の問題を回避するために、すぐにセッションを閉じる必要があります。

別の言い方をすれば、ロールバックは、永続エンティティに対して行ったメモリ内の変更をロールバックしません。

また、セッションが通常のセッションの場合、インスタンスは既に NH によって追跡されているため、Save() の呼び出しは必要ありません。

于 2012-11-14T15:30:06.513 に答える