我想完全像这样从 NHibernate 的 SqlClientBatchingBatcher 类继承(代码取自 带有加密触发器的 TooManyRowsAffectedException):
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();
}
}
请注意此处方法中访问的一些成员(如 currentBatch 或 totalExpectedRowsAffected)。
好吧,事实证明这些成员实际上是当前 NHibernate 3.3 源的超类中的私有成员。那么如何在不复制整个内容的情况下有效地继承类呢?顺便说一下,这是该类的未修改的 NHibernate 代码:
public class SqlClientBatchingBatcher : AbstractBatcher
{
private int _batchSize;
private int _totalExpectedRowsAffected;
private SqlClientSqlCommandSet _currentBatch;
private StringBuilder _currentBatchCommandsLog;
private readonly int _defaultTimeout;
public SqlClientBatchingBatcher(ConnectionManager connectionManager, IInterceptor interceptor)
: base(connectionManager, interceptor)
{
_batchSize = Factory.Settings.AdoBatchSize;
_defaultTimeout = PropertiesHelper.GetInt32(Cfg.Environment.CommandTimeout, Cfg.Environment.Properties, -1);
_currentBatch = CreateConfiguredBatch();
//we always create this, because we need to deal with a scenario in which
//the user change the logging configuration at runtime. Trying to put this
//behind an if(log.IsDebugEnabled) will cause a null reference exception
//at that point.
_currentBatchCommandsLog = new StringBuilder().AppendLine("Batch commands:");
}
public override int BatchSize
{
get { return _batchSize; }
set { _batchSize = value; }
}
protected override int CountOfStatementsInCurrentBatch
{
get { return _currentBatch.CountOfCommands; }
}
public override void AddToBatch(IExpectation expectation)
{
_totalExpectedRowsAffected += expectation.ExpectedRowCount;
IDbCommand batchUpdate = CurrentCommand;
Driver.AdjustCommand(batchUpdate);
string lineWithParameters = null;
var sqlStatementLogger = Factory.Settings.SqlStatementLogger;
if (sqlStatementLogger.IsDebugEnabled || Log.IsDebugEnabled)
{
lineWithParameters = sqlStatementLogger.GetCommandLineWithParameters(batchUpdate);
var formatStyle = sqlStatementLogger.DetermineActualStyle(FormatStyle.Basic);
lineWithParameters = formatStyle.Formatter.Format(lineWithParameters);
_currentBatchCommandsLog.Append("command ")
.Append(_currentBatch.CountOfCommands)
.Append(":")
.AppendLine(lineWithParameters);
}
if (Log.IsDebugEnabled)
{
Log.Debug("Adding to batch:" + lineWithParameters);
}
_currentBatch.Append((System.Data.SqlClient.SqlCommand) batchUpdate);
if (_currentBatch.CountOfCommands >= _batchSize)
{
ExecuteBatchWithTiming(batchUpdate);
}
}
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;
try
{
rowsAffected = _currentBatch.ExecuteNonQuery();
}
catch (DbException e)
{
throw ADOExceptionHelper.Convert(Factory.SQLExceptionConverter, e, "could not execute batch command.");
}
Expectations.VerifyOutcomeBatched(_totalExpectedRowsAffected, rowsAffected);
_currentBatch.Dispose();
_totalExpectedRowsAffected = 0;
_currentBatch = CreateConfiguredBatch();
}
private SqlClientSqlCommandSet CreateConfiguredBatch()
{
var result = new SqlClientSqlCommandSet();
if (_defaultTimeout > 0)
{
try
{
result.CommandTimeout = _defaultTimeout;
}
catch (Exception e)
{
if (Log.IsWarnEnabled)
{
Log.Warn(e.ToString());
}
}
}
return result;
}
}
我忽略了什么吗?复制整个内容以覆盖对任何私有成员的所有访问权限似乎是一种相当糟糕的方法。我只想覆盖一种方法!