2010-03-05 4 views
5

우리는 NHibernate를 사용하는 도메인을 지속하는 응용 프로그램에 Microsoft Sync Framework를 구현하려고합니다.Nhibernate와 Microsoft Sync Framework의 충돌 TooManyRowsAffectedexception

우리가 만난 문제 중 하나는 동기화 프레임 워크가 초기 데이터베이스 구조 (섀도우 테이블과 트리거 추가)를 변경 한 후 데이터베이스에 객체를 삽입하려고 할 때 toomanyrowsaffectedexception을 던져서 Hibernate가 당황하는 것입니다.

각 업데이트 문 주위에 SET NOCOUNT를 ON/OFF로 설정하는 방법이 있지만 테이블 구조가 nhibernate에 의해 자동으로 생성되고 동기화 트리거가 모든 트리거를 수동으로 조정하여 자동 생성되므로이 기사를 발견했습니다. 정말 옵션이 아닙니다. Where's the best place to SET NOCOUNT? 를하지만이 (-1 행이 영향을받는 일 예상)을 StaleStateException 결과 :

http://www.codewrecks.com/blog/index.php/2009/03/25/nhibernate-and-toomanyrowsaffectedexception/

는이 질문에 설명 된대로에 SQL Server 2008의 속성 NOCOUNT를 설정했습니다.

트리거에 자동으로 NOCOUNT 문을 설정하도록 동기화 프레임 워크를 구성하는 방법이 있는지 알고 있습니까? 아니면 NHibernate가 더 많거나 적은 행을 바꿀 것이라고 예상 할 수있는 방법이 있을까요? 또는 여러분 중 누구나이 NOCOUNT 문을 동기화 프레임 워크의 트리거에 추가하는 자동화 된 스크립트가있을 수 있습니다.

미리 Thx!

답변

6

나는 NOCOUNT 방식으로 가고 있다고 생각합니다. 동기화 프레임 워크에서 사용하는 모든 테이블에 대해 NOCOUNT를 설정하면됩니다. 아래 코드를 참조하십시오. 또 다른 방법은 NHibernate를 패치하고 updatecount를 무시하는 것입니다 (https://nhibernate.jira.com/browse/NH-1353).

KR,

class SqlSyncTriggerHelper 
{ 
    private const string triggerSql = @"select sys.triggers.name from sys.triggers, sys.objects 
     where sys.objects.name='{0}' and sys.objects.type = 'U' and sys.triggers.parent_id = sys.objects.object_id"; 

    private DbSyncScopeDescription syncScopeDescription; 

    public SqlSyncTriggerHelper(DbSyncScopeDescription syncScopeDescription) 
    { 
     this.syncScopeDescription = syncScopeDescription; 
    } 

    public void Apply(SqlConnection conn) 
    { 
     SqlTransaction transaction = null; 
     try 
     { 
      if (conn.State == System.Data.ConnectionState.Closed) 
      { 
       conn.Open(); 
      } 
      transaction = conn.BeginTransaction(); 
      foreach (var table in syncScopeDescription.Tables) 
      { 
       foreach (string trigger in GetTriggers(table.UnquotedLocalName, conn, transaction)) 
       { 
        AlterTrigger(trigger, conn, transaction); 
       } 
      } 
      transaction.Commit(); 
     } 
     catch 
     { 
      if (transaction != null) 
      { 
       transaction.Rollback(); 
      } 
      throw; 
     } 
     finally 
     { 
      if (transaction != null) 
      { 
       transaction.Dispose(); 
      } 
      conn.Close(); 
     } 
    } 

    private void AlterTrigger(string trigger, SqlConnection conn, SqlTransaction transaction) 
    { 
     SqlCommand newCmd = new SqlCommand(string.Format("exec sp_helptext '{0}'", trigger), conn, transaction); 
     var triggerStringBuilder = new StringBuilder(); 
     using (var reader = newCmd.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       triggerStringBuilder.Append(reader.GetValue(0) as string); 
      } 
     } 
     var triggerString = triggerStringBuilder.ToString(); 
     triggerString = triggerString.Replace("CREATE TRIGGER", "ALTER TRIGGER").Replace(" AS\n", " AS\nSET NOCOUNT ON\n") + "\nSET NOCOUNT OFF"; 
     var alterTriggerCommand = new SqlCommand(triggerString, conn, transaction); 
     alterTriggerCommand.ExecuteNonQuery(); 
    } 

    private IEnumerable<string> GetTriggers(string tableName, SqlConnection conn, SqlTransaction transaction) 
    { 
     var resultList = new List<string>(); 
     var command = new SqlCommand(string.Format(triggerSql, tableName), conn, transaction); 
     using (var reader = command.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       resultList.Add(reader.GetString(0)); 
      } 
     } 
     return resultList; 
    } 
} 
관련 문제