TooManyRowsActedException с зашифрованными триггерами - PullRequest
13 голосов
/ 30 августа 2009

Я использую nHibernate для обновления 2 столбцов в таблице с 3 зашифрованными триггерами. Триггеры не принадлежат мне, и я не могу вносить в них изменения, поэтому, к сожалению, я не могу установить NOCOUNT ON в них.

Есть ли другой способ обойти исключение TooManyRowsActedException, которое генерируется при коммите?

Обновление 1

Пока что единственный способ обойти эту проблему - обойти процедуру .Save с помощью

var query = session.CreateSQLQuery("update Orders set Notes = :Notes, Status = :Status where OrderId = :Order");
query.SetString("Notes", orderHeader.Notes);
query.SetString("Status", orderHeader.OrderStatus);
query.SetInt32("Order", orderHeader.OrderHeaderId);
query.ExecuteUpdate();

Он кажется грязным и его нелегко вытянуть, но он не растрескивается.

Ответы [ 3 ]

22 голосов
/ 23 апреля 2010

У нас была такая же проблема со сторонней базой данных Sybase. К счастью, после некоторого изучения кода NHibernate и краткого обсуждения с разработчиками кажется, что есть простое решение, которое не требует изменений в NHibernate. Решение дано Фабио Мауло в этой теме в группе разработчиков NHibernate .

Чтобы реализовать это для Sybase, мы создали нашу собственную реализацию IBatcherFactory, унаследованную от NonBatchingBatcher, и переопределили метод AddToBatch (), чтобы удалить вызов VerifyOutcomeNonBatched () для предоставленного объекта IExpectation:

public class NonVerifyingBatcherFactory : IBatcherFactory
{
    public virtual IBatcher CreateBatcher(ConnectionManager connectionManager, IInterceptor interceptor)
    {
        return new NonBatchingBatcherWithoutVerification(connectionManager, interceptor);
    }
}

public class NonBatchingBatcherWithoutVerification : NonBatchingBatcher
{
    public NonBatchingBatcherWithoutVerification(ConnectionManager connectionManager, IInterceptor interceptor) : base(connectionManager, interceptor)
    {}

    public override void AddToBatch(IExpectation expectation)
    {
        IDbCommand cmd = CurrentCommand;
        ExecuteNonQuery(cmd);
        // Removed the following line
        //expectation.VerifyOutcomeNonBatched(rowCount, cmd);
    }
}

Чтобы сделать то же самое для SQL Server, вам нужно унаследовать от SqlClientBatchingBatcher, переопределить DoExectuteBatch () и удалить вызов VerifyOutcomeBatched () из объекта Expectations:

public class NonBatchingBatcherWithoutVerification : SqlClientBatchingBatcher
{
    public NonBatchingBatcherWithoutVerification(ConnectionManager connectionManager, IInterceptor interceptor) : base(connectionManager, interceptor)
    {}

    protected override void DoExecuteBatch(IDbCommand ps)
    {
        log.DebugFormat("Executing batch");
        CheckReaders();
        Prepare(currentBatch.BatchCommand);
        if (Factory.Settings.SqlStatementLogger.IsDebugEnabled)
        {
            Factory.Settings.SqlStatementLogger.LogBatchCommand(currentBatchCommandsLog.ToString());
            currentBatchCommandsLog = new StringBuilder().AppendLine("Batch commands:");
        }

        int rowsAffected = currentBatch.ExecuteNonQuery();

        // Removed the following line
        //Expectations.VerifyOutcomeBatched(totalExpectedRowsAffected, rowsAffected);

        currentBatch.Dispose();
        totalExpectedRowsAffected = 0;
        currentBatch = new SqlClientSqlCommandSet();
    }
}

Теперь вам нужно добавить новые классы в NHibernate. Есть два способа сделать это, о которых я знаю:

  1. Укажите имя вашей реализации IBatcherFactory в свойстве конфигурации adonet.factory_class
  2. Создание пользовательского драйвера, который реализует интерфейс IEmbeddedBatcherFactoryProvider

Учитывая, что в нашем проекте уже был пользовательский драйвер для решения проблем со строками Sybase 12 ANSI, было просто изменить интерфейс следующим образом:

public class DriverWithCustomBatcherFactory : SybaseAdoNet12ClientDriver, IEmbeddedBatcherFactoryProvider
{
    public Type BatcherFactoryClass
    {
        get { return typeof(NonVerifyingBatcherFactory); }
    }

    //...other driver code for our project...
}

Драйвер можно настроить, указав имя драйвера с помощью свойства конфигурации connection.driver_class. Мы хотели использовать Fluent NHibernate, и это можно сделать с помощью Fluent следующим образом:

public class SybaseConfiguration : PersistenceConfiguration<SybaseConfiguration, SybaseConnectionStringBuilder>
{
    SybaseConfiguration()
    {
        Driver<DriverWithCustomBatcherFactory>();
        AdoNetBatchSize(1); // This is required to use our new batcher
    }

    /// <summary>
    /// The dialect to use
    /// </summary>
    public static SybaseConfiguration SybaseDialect
    {
        get
        {
            return new SybaseConfiguration()
                .Dialect<SybaseAdoNet12Dialect>();
        }
    }
}

и при создании фабрики сеансов мы используем этот новый класс следующим образом:

var sf = Fluently.Configure()
    .Database(SybaseConfiguration.SybaseDialect.ConnectionString(_connectionString))
    .Mappings(m => m.FluentMappings.AddFromAssemblyOf<MyEntity>())
    .BuildSessionFactory();

Наконец, вам нужно установить для свойства adonet.batch_size значение 1, чтобы обеспечить использование нового класса дозатора. В Fluent NHibernate это делается с помощью метода AdoNetBatchSize () в классе, который наследуется от PersistenceConfiguration (пример этого см. В конструкторе класса SybaseConfiguration выше).

1 голос
/ 02 мая 2012

Установка для параметра « Запретить результаты от триггеров » значения 1 работала для нас (по умолчанию 0).

Обратите внимание, что этот параметр не будет доступен в будущих выпусках Microsoft SQL Server, но после того, как он больше не будет доступен, он будет вести себя так, как если бы он был установлен на 1. Таким образом, установка этого значения на 1 теперь устраняет проблему и также дает у вас такое же поведение, как и в будущих выпусках.

1 голос
/ 30 августа 2009

э-э ... вы могли бы иметь возможность расшифровать их ...

Редактировать: если вы не можете изменить код, расшифровать или отключить, у вас нет параметров code на стороне SQL Server.

Однако вы можете попробовать " запретить результаты от триггеров Опция ", что нормально для SQL 2005 и SQL 2008, но будет удалено в более поздних версиях. Я не знаю, подавляет ли он сообщения о количестве строк.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...