Microsoft Sync Framework конфликтует с Nhibernate TooManyRowsAffectedexception - PullRequest
5 голосов
/ 05 марта 2010

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

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

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

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

Я попытался настроить сервер sqlСвойство 2008 NOCOUNT включено, как описано в этом вопросе: Где лучшее место для SET NOCOUNT? , но это привело к исключению StaleStateException (затронуты -1 строки, ожидается 1).

Ребята, вы знаете, как?w если есть способ настроить среду синхронизации для автоматической установки этих операторов NOCOUNT в ее триггерах?Или, может быть, есть способ сообщить NHibernate, что следует ожидать изменения большего или меньшего количества строк?Или, может быть, у любого из вас есть автоматический скрипт для добавления этих операторов NOCOUNT в триггеры каркаса синхронизации.

Заранее спасибо!

1 Ответ

6 голосов
/ 10 марта 2010

Я думаю, что путь NOCOUNT - это путь. Вы можете сделать это, установив NOCOUNT для всех таблиц, используемых структурой синхронизации. Смотрите код ниже. Другим способом является исправление NHibernate и игнорирование счетчика обновлений, см. (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;
    }
}
...