2009-03-10 10 views
7

私はFluent NHibernateを学んでいます。私は半永久的なPersistenceSpecificationクラスを実行しました。Fluent NHibernateのPersistenceSpecificationsで作成されたレコードをロールバックする

私はマッピングを検証するために単体テストで設定しました。ただし、完了するとデータベースにレコードが残されます。変更をロールバックできるようにトランザクションで投げてみましたが、エラーが発生します。

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(); 
      } 
+0

また、VerifyTheMappings呼び出しをSystem.EnterpriseServices.ServiceDomain.Enter()およびSetAbort()/ Leave()でラップすることも機能することがわかりました。 –

答えて

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(); 
} 
+0

私の投票を、私が探していたものとまったく同じにします! – cgreeno

+0

System.Data.IsolationLevelではなく、System.Transactions.IsolationLevel ... – rohancragg

2

PersistenceSpecificationは、通常はそれが何かをロールバックしない理由です、SQLiteのようなインメモリデータベースで使用されています。私は、ISessionインスタンスを取るコンストラクタのオーバーロードがあると信じています。

+0

うん、私はSessionFactory.OpenSession()コールから自分自身のISessionオブジェクトを作成した。そこからトランザクションを開始し、VerifyTheMappings()コールの後にトランザクションをロールバックしようとしましたが、エラーが発生しました。私は以下の完全なコードスニペットを投稿します。 –

2

ここで、VerifyTheMappings()はデータベースにtx.Commit()を実行するTransactionSave()を呼び出していると思います。ジェームズが指摘したように、この手法はメモリ内のテスト技術を捨て去るのに最適です。これはではなく、従来のデータベースとのマッピングをテストする場合にはになります。

0

実際のデータベースでこのテストを行うことは非常に重要だと思います。テーブル定義を確認することができます。マップされたエンティティで厳しいテストを実行し、終わり;クラスはnunit.frameworkを使用しているが、uはuが供給する必要がsessionfactoryprovider

をしたいすべてのテストフレームワークでそれを行うことができます

私のプロジェクトで

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は私のエンティティの最も基本的なインタフェースでありますここ

OBJ isessionは、使用のサンプルです

/// <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(); 

    } 
} 
1

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

これを行う正しい方法は、トランザクションを手動でロールバックすることです。トランザクションがコミットされると、Session.Transactionは自動的に置き換えられます。したがって、参照を保持する必要があります。TransactionalSave()は、現在のトランザクションがアクティブであるかどうかをチェックし、そのトランザクションを作成(および廃棄)します。もしそうでなければ自分自身。 、

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日にthis commitで修正されました!明らかに、これはもともととにかくやっていたことです。

関連する問題