2009-11-19 9 views
5

NHibernate와 매핑되지 않은 레거시 엔티티와 함께 ​​NHibernate를 사용하려고합니다. 가끔은 NHibernate 매핑 된 엔티티와 레거시 엔티티를 연결하려고 할 때 외래 키 예외를받지 못하도록 수동으로 NHibernate 데이터를 데이터베이스로 플러시해야 함을 의미합니다.여전히 트랜잭션 롤백을 허용하면서 NHibernate를 플러시

트랜잭션을 롤백해야 할 때이 문제가 발생하면 문제가 발생합니다. NHibernate에서 플러시 된 데이터는 롤백되지 않습니다.

내가 할 수있는 일이 있습니까?

이 작업을 수행하는 방법에 여전히 호기심 UPDATE - 나는 주소에게 문제를 주어진 답변 중 하나를 믿지 않는다. 나는 Flush()를 호출해야합니다. 문제는 플러시 된 데이터를 어떻게 롤백합니까?

+0

왜 내가 downvote 알려주십시오? 현재 답변은 좋지만 문제를 해결하지는 않습니다. NHibernate가 아닌 관리 쿼리가 NHibernate에 의해 업데이트 된 데이터에 액세스 할 수 있도록 데이터베이스에 플러시 할 수 있어야합니다. flush를 호출 할 수 없다면, NHibernate가 아닌 관리 쿼리가 데이터에 액세스 할 수있는 다른 방법은 없을까요? 상상해보십시오. 간단한 System.Data.SqlClient 호출로이 작업을 직접 처리 할 수 ​​있습니다. 매우 간단합니다. SqlCommand.ExecuteUpdate() 호출을 TransactionScope에서 랩핑하면 그게 전부입니다. 트랜잭션을 중첩하거나 롤백 할 수 있으며 모든 것이 예상대로 작동합니다. – cbp

답변

2

NHibernate와 트랜잭션을 사용하는 경우 Session.Flush()를 사용하지 말고 대신 session.flush()를 내부적으로 호출하는 transaction.Commit()를 사용하십시오.

Commit() 중에 오류가 발생하여 트랜잭션을 롤백해야하는 경우이 문제를 해결할 수 있습니다.

public static void CommitChanges() 
{ 
    ITransaction transaction = Session.BeginTransaction(); 

    try 
    { 
     transaction.Commit(); 
    } 
    catch (HibernateException ex) 
    { 
     transaction.Rollback(); 
     //close and dispose session here 
     throw ex; 
    } 
    finally 
    { 
     transaction.Dispose(); 
    } 
} 
이제

, 수동 호출 플러시하는 경우() 또는 전화 커밋()는 성공적으로 NHibernate에 메커니즘을 사용하여 트랜잭션을 롤백 할 수있는 방법이 없다 통해 간다. 특히 transaction.Commit() 명령을 호출 할 때 NHibernate에 의해 생성 된 AdoTransaction은 Commit()이 완료된 직후 처리되므로 롤백하기 위해 액세스 할 수 없습니다.

위 코드 샘플을 사용하면 커밋 중에 발생한 오류를 catch 한 다음 이미 시작한 트랜잭션을 롤백 할 수 있습니다.

위의 샘플에서 transaction.Commit()를 호출하는 대신 내 테스트에서 session.Flush()를 호출하면 트랜잭션이 커밋되지 않으므로 데이터가 데이터베이스에 저장되지 않습니다.

코드가 어떻게 보이는지는 모르겠지만 패턴을 호출하는 경우 위의 코드 샘플에서와 같이 Session.Flush() 대신 transaction.commit()을 사용하면 당신이 원하는 것을 성취하십시오.

+0

catch (...) 섹션은 기능적으로 아무 것도 추가하지 않습니다. Dispose()는 이미 커밋되지 않은 경우 롤백을 수행하기 때문입니다. – tofi9

+0

@taoufik 귀하의 의견은 잘못되었습니다. NHibernate 코드에서 AdoTransaction 객체에 의해 구현 된 ITransaction 인터페이스의 Dispose() 명령은 관리되는 리소스와 관리되지 않는 리소스를 해제하는 역할을합니다. 또한 Hibernate 소스 코드에 대한 간단한 살펴보기는 Dispose()가 ITransaction.RollBack() 또는 기본 IDbTransaction 객체의 RollBack() 메소드를 호출하지 않는다는 사실을 증명했습니다 ... 따라서 catch (...) 섹션은 전적으로 기능적이며 위의 코드 샘플에 필요합니다. – tolism7

+0

다음 게시물은 Dispose가 Rollback을 호출한다는 것을 증명하는 Reflector의 코드 단편을 보여줍니다. http : // stackoverflow.com/questions/641660/will-a-using-statement-rollback-a-database-transaction-if-an-error-occur – tofi9

3

형식화를 위해 나는 여기에 tolism7의 대답을 업데이트 할 수 있습니다.

  1. 사용 using 및 transaction.Dispose (잊어 참조) - transaction 자동하여 블록의 끝에서의 Dispose '(D)가 될 것이다.
  2. throw - 그것은 당신의 스택 트레이스 멀리 던지는 의미하기 때문에 예를 포기하지 않습니다 (이 상태 어디에 this post을 볼 "은 .NET Framework이 문을 실행하면 :. throw ex;를가 현재 함수 위의 모든 스택 정보를 버린다")를

. 이 코드 조각의 VB.NET version

public void CommitChanges() 
{ 
    using (var transaction = Session.BeginTransaction()) // <-- open scope 
     try 
     { 
      // do something 
      transaction.Commit(); 
     } 
     catch (HibernateException) 
     { 
      transaction.Rollback(); 
      _session.Close(); 
      _session.Dispose(); 

      throw; // <-- this way the stacktrace stays intact! 
     } 
} 

here를 찾을 수 있습니다.

4

확인이 : 저도 같은 문제가있는 듯 Force query execution without flush/commit

, 내가 세척 것하고 내가 롤백 것이지만, 일부 데이터가 데이터베이스에 지속 상태를 유지한다. 그러나 내 코드에는 롤백 할 수없는 커밋을 호출하는 부분이있었습니다. 허용 된 응답의 코드 스 니펫을 트랜잭션, 플러시, 롤백 및 커밋에 대한 적절한 사용으로 간주하고이 패턴을 확장 할 수 있다는 점을 고려하십시오. ...

단일 작업 단위로 요청을 고려합니다. 해당 요청에서 일어나는 웹 단일 작업 단위로 응용 프로그램과 모든) onEndRequest이 커밋 단일 트랜잭션에 존재 :

  1. 는 한 번만 _sessionFactory.OpenSession(), _session.BeginTransaction(), _session.CommitTransaction()_session.CloseSession()를 호출합니다.

  2. 당신은 _session.Flush()_session.RollBackTransaction()을 원하는만큼 여러 번 호출 할 수 있지만, 자동으로 커밋시 Flush()가 자동으로 호출됩니다. 쿼리를 작성하고 가져온 데이터가 오래 보관되지 않도록해야 할 때 플러시를 호출 할 수 있습니다.

  3. 일단 커밋 트랜잭션이 커밋되면 이후의 모든 작업은 해당 트랜잭션에서 발생하지 않습니다. 대신 NHibernate에 당신은 이미 당신이 정말로 당신의 작품 단위의 중간에 커밋 호출해야하는 경우

  4. 가 강력하게 권장 문제는 일관성과 가능성 논리적 무결성을 추적해야 하는 점에서 후드 (http://www.nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions)에서 필요한 트랜잭션을 생성합니다 특정 시점에 새 트랜잭션을 생성하여 명시 적으로 관리 할 수 ​​있습니다.

  5. 중첩 트랜잭션은 부분 커밋을 허용하는 것으로 추정됩니다. "루트"트랜잭션을 롤백하면 모든 변경 사항이 되돌려집니다. .NET과 SQL Server의이 기능을 실제로 테스트하지는 않았습니다. 데이터베이스 자체의 중첩 된 트랜잭션이 많이 필요하기는하지만 ADO.NET이이 기능을 얼마나 정확하게 구현하는지 알지 못합니다.

포인트 1 - 4는 1.2에서 시작하는 모든 버전의 NHibernate에서 테스트되었습니다.

+0

귀하의 의견을 보내 주셔서 감사합니다. 테스트에서 데이터가 플러시되면 트랜잭션을 롤백 할 수없는 경우가 종종 있습니다. 이것이 내가 두통의 원인이되기도합니다. 때로는 트랜잭션을 통해 부분적으로 플러시해야하지만 나중에 트랜잭션을 롤백 할 수 있어야합니다. 이것은 NHibernate로는 불가능한 것처럼 보인다. – cbp

+0

플러시 된 경우 완벽하게 롤백 할 수 있습니다. db 작업을 프로파일 링해야합니다. 아마도 커밋을 호출하거나 커밋을 유발할 수 있습니다. 나는 명확하고 암시적인 플러시 (예를 들어 hql/criteria 쿼리를 만들 때)를 수행하고 문제없이 트랜잭션이 끝날 때 롤백 (예외 또는 테스트)을 수행했습니다. – Jaguar

관련 문제