7

Fluent NHibernate を学んでいて、半素晴らしい PersistenceSpecification クラスに出くわしました。

マッピングを検証するために単体テストでセットアップしましたが、うまく機能します。ただし、完了時にレコードがデータベースに残ります。変更をロールバックできるようにトランザクションにスローしようとしましたが、エラーが発生します。

System.ObjectDisposedException: 破棄されたオブジェクトにアクセスできません。オブジェクト名: 'AdoTransaction'..

トランザクションがなければ、レコードの ID を把握し、それらを取得して削除する必要がありますが、これはあまり洗練されていません。

何かご意見は?

編集:

コード スニペットは次のとおりです。

            var factory = GetSessionFactory();
            using (var session = factory.OpenSession())
            using (var transaction = session.BeginTransaction())
            {
                new PersistenceSpecification<TimePeriod>(session)
                        .CheckProperty(x => x.EndDate, DateTime.Today)
                        .VerifyTheMappings();
                transaction.Rollback();
            }
4

5 に答える 5

9

トランザクションで IsolationLevel を設定してみてください。このスニペットは私のために働いた:

using (var trans = _session.BeginTransaction(IsolationLevel.ReadUncommitted))
{
    new PersistenceSpecification<Event>(_session)
        .CheckProperty(p => p.StartTime, new DateTime(2010, 1, 1))
        .VerifyTheMappings();
    trans.Rollback();
}
于 2010-01-03T10:27:02.197 に答える
2

ここでの問題は、VerifyTheMappings()がTransactionSave()を呼び出し、データベースに対してtx.Commit()を実行することだと思います。Jamesが指摘したように、この手法はメモリ内のテスト手法を破棄するのに最適なようです。これは、レガシーデータベースに対してマッピングをテストする場合には機能しません。

于 2009-06-18T01:19:07.307 に答える
2

PersistenceSpecification通常、SQLite のようなメモリ内データベースで使用されるため、何もロールバックしません。インスタンスを取るコンストラクターのオーバーロードがあるとISession思いますが、そこからトランザクションを取得してからロールバックしようとしましたか?

于 2009-03-11T08:53:40.053 に答える
1

設定IsolationLevel.ReadUncommittedは機能しますが、それが行っているのはセッションに、新しいトランザクション (DBMS 用語でのダーティ リード) を必要とせずに読み取ることができることを伝えることだけであるためSession.Transaction.Commit ()、検証が読み取られる前にデータベース トランザクションをコミットする必要はありません。 . これはまた、テストしていると思われるものを必ずしもテストしているとは限らないことも意味します! (これは、MS SQL 以外のデータベース間でおそらく疑わしいサポートをしていると思います)。leebrandt からの回答は、分離レベルではなく、明示的なロールバックのために機能します (nb。回答の時点で、これは現在よりも役立ちました。以下の注を参照してください)。

幸いなことに、これを行う正しい方法は、トランザクションを手動でロールバックすることです。Session.Transactionトランザクションがコミットされるたびに自動的に置き換えられるため、それへの参照を保持する必要があり、とにかく明示的に開く必要があります。TransactionalSave ()現在のトランザクションがアクティブであるかどうかをチェックし、独自の ifいいえ。私は通常、すべてのマッピングを同じフィクスチャでテストします。ここでは、ファクトリの作成と他のいくつかのインフラストラクチャの永続性も確認します。そのため、配管を抑えるために次のパターンが好きです。

class TestFixture {
    static ISessionFactory factory = CreateMyFactorySomehowHere();

    ISession session;
    ITransaction tx;

    public void Setup ()
    {
        session = factory.OpenSession ();
        tx = session.BeginTransaction ();
    }

    public void Cleanup ()
    {
        tx.Rollback ();
        tx.Dispose ();
        session.Close ();
    }

    public void TestAMappingForSomething ()
    {
        var spec = new PersistenceSpecification<Something> (session);
        spec.VerifyTheMappings ();
    }
}

明らかに、独自のテストフレームワーク固有の用語と属性/注釈をどこにでも挿入しますが、アイデアはわかります。


私は今、この質問がどれほど古いものであるかに気付きました: この動作は7 月 9 日のこのコミットで修正され、既存のトランザクションを適切に処理して上記が機能するようになりました! 明らかに、これはとにかくもともとあなたがしていたことです。

于 2011-03-09T03:06:26.050 に答える
0

実際のデータベースでこのテストを実行して、彼のテーブル定義が問題ないことを確認することが非常に重要だと思います。そのため、マップされたエンティティで crud テストを実行し、最後にロールバックする非常に単純なクラスを開発しました。

 internal class GenericMappingTesterWithRealDB<T> where T : IIdentifiable
{
    public T EntityToTest { get; set; }
    public Func<T, object> PerformEntityManipulationBeforeUpdate { get; set; }
    public GenericMappingTesterWithRealDB()
    {
        Assume.That(SessionFactoryProvider.NewSession,Is.Not.Null);
    }

    public void RunTest()
    {
        using (ISession session = SessionFactoryProvider.NewSession)
        using (ITransaction transaction = session.BeginTransaction())
        {
            try
            {
                session.Save(EntityToTest);
                var item = session.Get<T>(EntityToTest.ID);
                Assert.IsNotNull(item);
                if (PerformEntityManipulationBeforeUpdate != null)
                {
                    PerformEntityManipulationBeforeUpdate.Invoke(EntityToTest);
                }
                session.Update(EntityToTest);
                session.Delete(EntityToTest);
                session.Save(EntityToTest);
            }
            catch (Exception e)
            {
                Assert.Fail(e.Message, e.StackTrace);
            }
            finally
            {
                transaction.Rollback();
            }
        }
    }
}

私のプロジェクトの IIdentifiable は、エンティティの最も基本的なインターフェイスです

クラスはnunit.frameworkを使用していますが、必要なすべてのテストフレームワークで実行できます

sessionfactoryprovider は isession obj を提供する必要があります

使用例はこちら

/// <summary>
/// Testing the mapping of our entities.
/// there must be a server connection for this kind of test.
/// </summary>
[TestFixture]
internal class someMappingTest
{
    [Test(Description = "Check the Encoding Profile FluentNHibernate Mapping")]
    [Timeout(20000)]
    public void checkthatMappingWorks()
    {
        // creatw the new entity
        TestedType testOn = new TestedType();

        // set the initialization values
        testOn.Name = "TestProfileExecution";

        // create the test object
        new GenericMappingTesterWithRealDB<TestedType>
        {
            // assign an entity
            EntityToTest = testOn,

            // assign new values for update check
            PerformEntityManipulationBeforeUpdate =
                delegate(TestedType testedTypeBeingTested)
                    {
                        return testedTypeBeingTested.Name = "Updateing Test";
                    }
        }.
        // call run test to perform the mapping test.
        RunTest();

    }
}
于 2009-08-15T14:29:04.467 に答える