2010-03-05 2 views
5

Мы пытаемся внедрить Microsoft Sync Framework в наше приложение, которое сохраняет домен с помощью NHibernate.Microsoft Sync Framework сталкивается с Nhibernate TooManyRowsAffectedexception

Одна из проблем, с которыми мы столкнулись, заключается в том, что после того, как Sync Framework изменила вашу исходную структуру базы данных (добавив теневые таблицы и триггеры), NHibernate, похоже, расстраивается, бросая исключение toomanyrowsaffected при попытке вставить объекты в базу данных.

Я нашел эту статью, в которой есть решение добавить SET NOCOUNT ON и OFF вокруг каждого оператора обновления, но так как структура таблицы автоматически генерируется nhibernate, а триггеры синхронизации автоматически генерируются в Sync Framework, настраивая все триггеры вручную на самом деле не вариант.

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

Я попытался установить свойство NOCOUNT SQL Server 2008, как это описано в этом вопросе: Where's the best place to SET NOCOUNT? , но это привело к StaleStateException (-1 строк затронуты, ожидается, 1).

Вы, ребята, знаете, есть ли способ настроить структуру синхронизации, чтобы автоматически устанавливать эти инструкции 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; 
    } 
}