Oracle 数据库无关存储过程API

Oracle 数据库无关存储过程API,oracle,stored-procedures,database-agnostic,Oracle,Stored Procedures,Database Agnostic,我们的传统web应用程序大量使用存储过程。我们有一个中央接口,通过该接口进行所有数据库调用(即查询和过程)。但是,当前的实现使用UndertheHood绑定到适当的存储过程签名。从文件中: DeriveParameters会导致数据库往返,并且只能在设计期间使用。 为了避免在生产环境中进行不必要的数据库往返 DeriveParameters方法本身应替换为显式参数设置 在设计时由DeriveParameters方法返回的 我们可以使用显式绑定到正确的存储过程签名。然而,将我们的代码(即使只是数据

我们的传统web应用程序大量使用存储过程。我们有一个中央接口,通过该接口进行所有数据库调用(即查询和过程)。但是,当前的实现使用UndertheHood绑定到适当的存储过程签名。从文件中:

DeriveParameters会导致数据库往返,并且只能在设计期间使用。 为了避免在生产环境中进行不必要的数据库往返 DeriveParameters方法本身应替换为显式参数设置 在设计时由DeriveParameters方法返回的

我们可以使用显式绑定到正确的存储过程签名。然而,将我们的代码(即使只是数据访问层)与OracleCommand对象混在一起并不是不可知数据库的。我们已经在数据库接口(以下简称IDatabaseService)中支持与数据库无关的动态查询,如下所示:

int ExecuteNonQuery(string query, object[] parameterValues);
IDataReader ExecuteReader(string query, object[] parameterValues);
// etc.
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);
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
}
我们还希望支持与数据库无关的存储过程调用。什么是好的模式

更多信息:


要绑定到特定的子例程,OracleCommand允许。我们不希望使用这种方法,因为字符串比类型更容易出错。绑定子例程调用的另一种方法是提供参数类型。我们可以依赖于参数值并反映运行时类型,但我们需要更高的安全性。我们希望将类型显式地提供给数据库接口,以便在与数据库通信之前检查提供的参数值是否与提供的子例程参数类型匹配。

在对各种方法进行原型设计之后,我们确定了以下几点。

在IDatabaseService中,我们添加了新的Executeyy方法,这些方法采用实现IDatabaseSubroutineSignature的对象和(可选地,通过重载)作为参数值的IEnumerable

IDatabaseService上的Executeyy方法如下所示:

int ExecuteNonQuery(string query, object[] parameterValues);
IDataReader ExecuteReader(string query, object[] parameterValues);
// etc.
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);
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
}
最后,这里是一个使用示例:

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));
        }
    }
}
私有静态只读IDatabaseSubroutineSignature MyProcedureSignature=
DatabaseSubroutineSignatureFactory.Create(“pkg.myprocedure”)
.Input(参数类型.Decimal)
.Input(ParameterType.String)
.输出(ParameterType.RefCursor);
公共IEnumerable CallMyProcedure(十进制用户ID、字符串搜索查询)
{
使用(IDatabaseService dbService=…)
使用(IDataReader dataReader=dbService.ExecuteReader)(MyProcedureSignature,
新对象[]{userId,searchQuery})
{
while(dataReader.Read())
{
返回新的数据对象(
dataReader.GetDecimal(0),
GetString(1));
}
}
}

那么您为Oracle支付了多少钱,但您想要一种完全通用/不可知的方法?如果您为Oracle付费,请使用它!如果没有,只需使用Postres或mysql或类似工具即可。只有我的2美分。@tbone我们无法控制我们的部署环境,但它可能会发生变化。我们正在为我们的客户希望切换到另一个DB平台的场景做准备。根据我的经验,中间件和/或前端更有可能在后端改变之前改变(特别是如果他们已经使用Oracle一段时间,并且已经开发了一层包/过程/功能)。@tbone这里不是这样。