在对各种方法进行原型设计后,我们选择了以下方法。
我们向IDatabaseService添加了新的 ExecuteYYY 方法,这些方法采用实现 IDatabaseSubroutineSignature 的对象和(可选地,通过重载)作为参数值的IEnumerable 。
IDatabaseService 上的ExecuteYYY方法如下所示:
DataSet ExecuteDataSet(IDatabaseSubroutineSignature signature);
DataSet ExecuteDataSet(IDatabaseSubroutineSignature signature, IEnumerable<object> parameterValues);
void ExecuteNonQuery(IDatabaseSubroutineSignature signature);
void ExecuteNonQuery(IDatabaseSubroutineSignature signature, IEnumerable<object> parameterValues);
IDataReader ExecuteReader(IDatabaseSubroutineSignature signature);
IDataReader ExecuteReader(IDatabaseSubroutineSignature signature, IEnumerable<object> parameterValues);
object ExecuteScalar(IDatabaseSubroutineSignature signature);
object ExecuteScalar(IDatabaseSubroutineSignature signature, IEnumerable<object> parameterValues);
ReadOnlyCollection<object> ExecuteScalarMultiple(IDatabaseSubroutineSignature signature);
ReadOnlyCollection<object> ExecuteScalarMultiple(IDatabaseSubroutineSignature signature, IEnumerable<object> parameterValues);
标准 .NET BCL ExecuteYYY 方法与上述方法之间存在一些差异:
- 我们的 ExecuteNonQuery 方法返回 void。这是因为 ExecuteNonQuery(在命令对象上)在执行存储过程时总是返回 -1。
- 我们引入了一个新的 ExecuteScalarMultiple 方法。这说明了多个输出参数。
IDatabaseSubroutineSignature如下所示:
public interface IDatabaseSubroutineSignature
{
string Name { get; }
IEnumerable<IDatabaseSubroutineParameter> Parameters { get; }
}
public interface IDatabaseSubroutineParameter
{
ParameterType Type { get; }
ParameterDirection Direction { get; }
}
// Using custom DbType attribute.
public enum ParameterType
{
[DbType(DbType.Decimal)]
Decimal,
[DbType(DbType.String)]
String,
[DbType(DbType.StringFixedLength)]
Character,
RefCursor,
[DbType(DbType.Double)]
Double,
[DbType(DbType.Int32)]
Int32,
[DbType(DbType.Int64)]
Int64,
[DbType(DbType.DateTime)]
DateTime
}
我们遇到的最后一个问题是用一种方便的方式在代码中创建(和表示)签名。我们通过创建 IDatabaseSubroutineSignature 的子接口确定了一种 monadesque 方法,该接口公开了创建参数的方法:
public interface IDatabaseSubroutineSignatureCreator : IDatabaseSubroutineSignature
{
IDatabaseSubroutineSignatureCreator Input(ParameterType dbType);
IDatabaseSubroutineSignatureCreator Output(ParameterType dbType);
IDatabaseSubroutineSignatureCreator InputOutput(ParameterType dbType);
IDatabaseSubroutineSignatureCreator ReturnValue(ParameterType dbType);
}
最后,这是一个使用示例:
private static readonly IDatabaseSubroutineSignature MyProcedureSignature =
DatabaseSubroutineSignatureFactory.Create("pkg.myprocedure")
.Input(ParameterType.Decimal)
.Input(ParameterType.String)
.Output(ParameterType.RefCursor);
public IEnumerable<DataObject> CallMyProcedure(decimal userId, string searchQuery)
{
using (IDatabaseService dbService = ...)
using (IDataReader dataReader = dbService.ExecuteReader(MyProcedureSignature,
new object[] { userId, searchQuery }))
{
while (dataReader.Read())
{
yield return new DataObject(
dataReader.GetDecimal(0),
dataReader.GetString(1));
}
}
}