2009-03-10 2 views
7

나는 Fluent NHibernate를 배우고 있으며, 반가운 PersistenceSpecification 클래스를 실행했다.Fluent NHibernate에서 PersistenceSpecifications에 의해 생성 된 레코드를 롤백하기

내 매핑을 확인하기 위해 유닛 테스트에서 설정 했으므로 훌륭하게 작동합니다. 그러나 완료되면 데이터베이스에 레코드가 남습니다. 변경 내용을 롤백 할 수 있도록 트랜잭션에서 throw했지만 오류가 발생합니다.

System.ObjectDisposedException : 폐기 된 개체에 액세스 할 수 없습니다. 개체 이름 : 'AdoTransaction'..

트랜잭션이 없으면 레코드의 ID를 찾아서 검색하고 삭제하면 매우 우아하지 않습니다.

의견이 있으십니까?

편집 : 그것은 다시 물건을 굴하지 않는 그 이유는,

PersistenceSpecification
  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.TData.IsolationLevel이 아닌 System.Data.IsolationLevel ... – rohancragg

2

보통 SQLite는 같은 메모리 데이터베이스와 함께 사용됩니다 : 여기

는 코드입니다. ISession 인스턴스를 사용하는 생성자 오버로드가 있다고 생각합니다. 거기에서 트랜잭션을 가져 와서 다시 시도해 보셨습니까?

+0

그래, SessionFactory.OpenSession() 호출에서 내 자신의 ISession 객체를 만들었습니다. 거기서부터 트랜잭션을 시작한 다음 VerifyTheMappings() 호출 후에 트랜잭션을 롤백하려고 시도하고 오류가 발생했습니다. 아래에 전체 코드 스 니펫을 게시합니다. –

2

여기 VerifyTheMappings()는 데이터베이스에 tx.Commit()을 수행하는 TransactionSave()를 호출하는 것이 문제라고 생각합니다. James가 지적했듯이이 기술은 메모리 내 테스트 기술을 폐기하는 데 효과적입니다. 레거시 데이터베이스에 대한 매핑을 테스트하는 경우 이 아닌이 작동합니다.

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의 대답은 명백한 롤백으로 격리 수준이 아니기 때문에 작동합니다. (nb는 대답 시점에이 점이 도움이되었습니다. 아래 참고 참조).

올바른 방법은 트랜잭션을 수동으로 롤백하는 것입니다. 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 월 09 this commit 수정되었습니다! 분명히 이것은 원래 어쨌든하고있는 일입니다.

관련 문제