TooManyRowsAffectedException with encrypted triggers
TooManyRowsAffectedException with encrypted triggers
我正在使用nHibernate来更新一个表中的2列,该表上有3个加密触发器。这些触发器不是我拥有的,我无法对它们进行更改,所以很遗憾我不能在它们内部设置SET NOCOUNT ON。
有没有其他方法来解决在提交时抛出的TooManyRowsAffectedException异常呢?
更新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();
感觉有些不太正规,而且不容易扩展,但至少不会崩溃。
问题原因:当我们使用加密触发器时,可能会遇到TooManyRowsAffectedException异常。这是因为加密触发器会导致返回的结果集变得不可用,从而触发异常。
解决方法:设置"Disallow Results from Triggers"选项为1可以解决该问题。注意,该选项在将来的Microsoft SQL Server版本中将不再可用,但在不可用之后,它将表现得就像设置为1一样。因此,现在将其设置为1可以修复问题,并且还可以获得与将来版本相同的行为。
代码示例:
-- 设置"Disallow Results from Triggers"选项为1 EXEC sp_configure 'Disallow Results from Triggers', 1; RECONFIGURE;
请注意,这只是一个临时解决方法,因为将来的SQL Server版本中将不再支持该选项。因此,在使用加密触发器时,我们可能需要寻找其他替代方案来避免出现TooManyRowsAffectedException异常。
问题的原因是由于NHibernate的默认行为,在使用加密触发器时,可能会导致TooManyRowsAffectedException异常。解决方法是通过创建自己的IBatcherFactory实现,然后重写AddToBatch方法,从提供的IExpectation对象中移除对VerifyOutcomeNonBatched方法的调用。
对于Sybase数据库,实现如下:
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); } }
对于SQL Server数据库,实现如下:
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(); currentBatch.Dispose(); totalExpectedRowsAffected = 0; currentBatch = new SqlClientSqlCommandSet(); } }
然后,将新的类注入到NHibernate中,有两种方法可以实现:
1. 在adonet.factory_class配置属性中提供自己的IBatcherFactory实现的名称。
2. 创建一个实现IEmbeddedBatcherFactoryProvider接口的自定义驱动程序。
对于Sybase数据库,创建自定义驱动程序如下:
public class DriverWithCustomBatcherFactory : SybaseAdoNet12ClientDriver, IEmbeddedBatcherFactoryProvider { public Type BatcherFactoryClass { get { return typeof(NonVerifyingBatcherFactory); } } //...other driver code for our project... }
然后,在配置文件中使用自定义驱动程序:
var sf = Fluently.Configure() .Database(SybaseConfiguration.SybaseDialect.ConnectionString(_connectionString)) .Mappings(m => m.FluentMappings.AddFromAssemblyOf<MyEntity>()) .BuildSessionFactory();
最后,将adonet.batch_size属性设置为1,以确保使用新的批处理类。
对于SQL Server数据库,需要复制整个SqlClientBatchingBatcher类,并将相关字段设置为可访问,然后进行相应的修改即可。
以上是解决TooManyRowsAffectedException with encrypted triggers问题的方法。
这篇文章讨论了一个名为"TooManyRowsAffectedException with encrypted triggers"的问题,以及它的出现原因和解决方法。
问题的出现原因是在使用具有加密触发器的数据库时,可能会出现TooManyRowsAffectedException异常。这通常是因为加密触发器在处理数据时导致了过多的行受到影响。
解决此问题的方法之一是尝试解密存储过程。如果能够成功解密存储过程,可能可以解决该问题。然而,这并不总是可行的,因为有些情况下可能无法更改代码或禁用触发器。
另一种解决方法是使用SQL Server提供的"disallow results from triggers Option"。这个选项可以用于SQL Server 2005和SQL Server 2008,但在以后的版本中将被移除。不过,不确定这个选项是否会抑制行数的消息。
总之,破解加密并不是一个可行的解决方法,因此需要尝试其他的解决方法来解决"TooManyRowsAffectedException with encrypted triggers"问题。