У нас была такая же проблема со сторонней базой данных 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. Есть два способа сделать это, о которых я знаю:
- Укажите имя вашей реализации IBatcherFactory в свойстве конфигурации adonet.factory_class
- Создание пользовательского драйвера, который реализует интерфейс 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 выше).