我正在使用nHibernate更新表中的2列,其中包含3个加密触发器。触发器不归我所有,我无法对它们进行更改,所以不幸的是我无法在它们内部设置NOCOUNT。
有没有其他方法可以解决在提交时抛出的TooManyRowsAffectedException?
到目前为止,我唯一能解决问题的方法是使用
来绕过.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();
它感觉很脏并且不容易伸展,但它没有陨石坑。
答案 0 :(得分:22)
第三方Sybase数据库遇到了同样的问题。幸运的是,在深入研究NHibernate代码并与开发人员进行简要讨论后,似乎有一个简单的解决方案,不需要更改NHibernate。解决方案由Fabio Maulo在this thread in the NHibernate developer group中提供。
为了实现这一点,我们创建了自己的IBatcherFactory实现,继承自NonBatchingBatcher并覆盖了AddToBatch()方法,以删除对提供的IExpectation对象的VerifyOutcomeNonBatched()调用:
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()并从Expectations对象中删除对VerifyOutcomeBatched()的调用:
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。我知道有两种方法可以做到这一点:
鉴于我们的项目中已经有一个自定义驱动程序来解决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,以确保使用新的batcher类。在Fluent NHibernate中,这是在继承自PersistenceConfiguration的类中使用AdoNetBatchSize()方法完成的(有关此示例,请参阅上面的SybaseConfiguration类构造函数)。
答案 1 :(得分:1)
编辑:如果您无法更改代码,解密或禁用,那么SQL Server端没有代码选项。
但是,您可以尝试“disallow results from triggers Option”,这对于SQL 2005和SQL 2008是可以的,但将在以后的版本中删除。我不知道它是否会抑制rowcount消息。
答案 2 :(得分:1)
将“Disallow Results from Triggers”选项设置为1对我们有用(默认值为0)。
请注意,此选项在Microsoft SQL Server的未来版本中将不可用,但在它不再可用后,它的行为就像设置为1.因此将此设置为1现在可以解决问题并同时提供你的行为与将来的版本相同。