2010-03-29 6 views
4

롤백 된 성 ActiveRecord TransactionScope를 사용할 때 문제를 해결하려고합니다.실패한 성 ActiveRecord TransactionScope는 향후 쿼리가 유효하지 않게 만듭니다.

롤백 후 Dog 테이블을 쿼리 할 수 ​​없습니다. DogMissingName을 삽입 할 수 없기 때문에 "Dog.FindFirst()"행은 "Dog에 대해 SlicedFindAll을 수행 할 수 없습니다"와 함께 실패합니다. 다음과 같이

using (new SessionScope()) 
{ 
    try 
    { 
     var trans = new TransactionScope(TransactionMode.New, OnDispose.Commit); 

     try 
     { 
      var dog = new Dog 
      { 
       Name = "Snowy" 
      }; 
      dog.Save(); 
      var dogMissingName = new Dog(); 
      dogMissingName.Save(); 
     } 
     catch (Exception) 
     { 
      trans.VoteRollBack(); 
      throw; 
     } 
     finally 
     { 
      trans.Dispose(); 
     } 
    } 
    catch (Exception ex) 
    { 
     var dogFromDatabase = Dog.FindFirst(); 
     Console.WriteLine("A dog: " + dogFromDatabase.Name); 
    } 
} 

스택 트레이스는 다음과 같습니다

Castle.ActiveRecord.Framework.ActiveRecordException: Could not perform SlicedFindAll for Dog ---> NHibernate.Exceptions.GenericADOException: could not insert: [Mvno.Dal.Dog#219e86fa-1081-490a-92d1-9d480171fcfd][SQL: INSERT INTO Dog (Name, Id) VALUES (?, ?)] ---> System.Data.SqlClient.SqlException: Cannot insert the value NULL into column 'Name', table 'Dog'; column does not allow nulls. INSERT fails. 
The statement has been terminated. 
    ved System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) 
    ved System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) 
    ved System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) 
    ved System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) 
    ved System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) 
    ved System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) 
    ved System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) 
    ved System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe) 
    ved System.Data.SqlClient.SqlCommand.ExecuteNonQuery() 
    ved NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd) 
    ved NHibernate.AdoNet.NonBatchingBatcher.AddToBatch(IExpectation expectation) 
    ved NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object id, Object[] fields, Boolean[] notNull, Int32 j, SqlCommandInfo sql, Object obj, ISessionImplementor session) 
    --- End of inner exception stack trace --- 
    ved NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object id, Object[] fields, Boolean[] notNull, Int32 j, SqlCommandInfo sql, Object obj, ISessionImplementor session) 
    ved NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object id, Object[] fields, Object obj, ISessionImplementor session) 
    ved NHibernate.Action.EntityInsertAction.Execute() 
    ved NHibernate.Engine.ActionQueue.Execute(IExecutable executable) 
    ved NHibernate.Engine.ActionQueue.ExecuteActions(IList list) 
    ved NHibernate.Engine.ActionQueue.ExecuteActions() 
    ved NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session) 
    ved NHibernate.Event.Default.DefaultAutoFlushEventListener.OnAutoFlush(AutoFlushEvent event) 
    ved NHibernate.Impl.SessionImpl.AutoFlushIfRequired(ISet`1 querySpaces) 
    ved NHibernate.Impl.SessionImpl.List(CriteriaImpl criteria, IList results) 
    ved NHibernate.Impl.CriteriaImpl.List(IList results) 
    ved NHibernate.Impl.CriteriaImpl.List() 
    ved Castle.ActiveRecord.ActiveRecordBase.SlicedFindAll(Type targetType, Int32 firstResult, Int32 maxResults, Order[] orders, ICriterion[] criteria) 
    --- End of inner exception stack trace --- 
    ved Castle.ActiveRecord.ActiveRecordBase.SlicedFindAll(Type targetType, Int32 firstResult, Int32 maxResults, Order[] orders, ICriterion[] criteria) 
    ved Castle.ActiveRecord.ActiveRecordBase.FindFirst(Type targetType, Order[] orders, ICriterion[] criteria) 
    ved Castle.ActiveRecord.ActiveRecordBase.FindFirst(Type targetType, ICriterion[] criteria) 
    ved Castle.ActiveRecord.ActiveRecordBase`1.FindFirst(ICriterion[] criteria) 
+0

게시 된 전체 스택 추적 –

+0

스택 추적을 게시하시기 바랍니다. – mbp

+0

TransactionScope를 사용하여 바깥 쪽 SessionScope를 바꾸면 작동한다는 점에 유의하십시오. – mbp

답변

3

당신은 스택 추적에서 보면, 당신은 잘못된 dogMissingName 기록은 여전히 ​​심지어 세션의 일괄 삽입 버퍼에 주위를 어슬렁 것을 깨달을 것입니다 경우 삽입을 처음 시도한 후에 실패했습니다. 나중에 같은 세션에서 Dog.FindFirst()를 호출 (다시 한 번 실패한 삽입을 시도한다.) 내부 Flush()를 재 - 트리거

를 문서의 section 9.6에서 :

시간이 지남에 따라 ISession이 실행됩니다 에 필요한 SQL 문은 ADO.NET 연결의 상태를 메모리에 의 개체 상태와 동기화합니다. ,, 세척이 과정은) (NHibernate.ITransaction.Commit에서 찾기() 또는 Enumerable에서()

  • 의 일부 호출() ISession.Flush에서
  • 에서

    • 다음과 같은 점에서 기본적으로 발생

      : 문서의 section 9.7.2에서 또한
  • ,

    트랜잭션을 롤백하는 경우 즉시 닫고 현재 세션을 버려야합니다. NHibernate의 내부 상태가 일관성을 유지하는지 확인하십시오.

    전자 이동 내부 using (new SessionScope())try/catch 가능한 대안 (초기 삽입 가능성에 제 실패 트리거링 SessionScope 아웃 걸릴 예외를 발생, 실패 할 수있다 동일한 삽입, 실패 마지막으로 catch - "data is not flushed on SessionScope.Flush()" 참조 : com.googlegroups.castle-project-users). 세션을 종료하지 않으려면

    또는, 당신은 단순히 change the session default flush behaviourFlush()가 명시 적으로 호출하지 않는 한이 플러시하지 않도록합니다 (FlushMode 클래스를 참조) 할 수 있어야한다 (예 : 커밋하기 전에.) 참고 이 방법으로 플러시를 관리하면 은 매우 복잡하고 오류가 발생하기 쉽습니다..

    2

    의 핵심은 블라드의 대답에 맞다 : 당신 해야 즉시 가까운 트랜잭션을 롤백하고 를 폐기하는 경우

    현재 세션이 자 NHibernate의 내부 상태에 일관성 있는지 확인합니다.

    이해하고 그것을 적용하면, 당신의 코드는 다음과 같아야합니다

    try 
    { 
        using (new SessionScope()) 
        using (var trans = new TransactionScope(TransactionMode.New, OnDispose.Commit)) 
        { 
         try 
         { 
          var dog = new Dog { Name = "Snowy" }; 
          dog.Save(); 
          var dogMissingName = new Dog(); 
          dogMissingName.Save(); 
         } 
         catch (Exception) 
         { 
          trans.VoteRollBack(); 
          throw; 
         } 
        } 
    } 
    catch (Exception ex) 
    { 
        using (new SessionScope()) 
        { 
         var dogFromDatabase = Dog.FindFirst(); 
         Console.WriteLine("A dog: " + dogFromDatabase.Name); 
        } 
    } 
    
    관련 문제