数据提供者抽象

时间:2018-01-19 13:51:40

标签: c# generics .net-4.6

我有一个场景,我需要将几个不同的数据提供者中的公共类成员抽象为一个公共类。当前的Data对象都派生自Db*命名空间中的各种System.Data.Common类。

以下是我当前的base实施:

public abstract class DataProvider<TConn, TCmd, TParam> : IDisposable
    where TConn : DbConnection, new()
    where TCmd : DbCommand, new() {

    public DataProvider ( string connstr ) {
        ConnectionString = connstr;
    }

    public TConn Connection { get { return new TConn(); } }
    public TCmd Command { get { return new TCmd(); } }
    public string ConnectionString { get; private set; }

    protected DbDataReader ExecuteReader ( string text , CommandType type , params TParam [] parms ) {
        try {
            using ( var conn = Connection ) {
                conn.Open();

                using ( var cmd = Command ) {
                    cmd.CommandText = text;
                    cmd.CommandType = type;
                    cmd.Parameters.AddRange( parms );

                    return cmd.ExecuteReader();
                }
            }
        } catch ( Exception ex ) {
            Log.Exception( ex , GetType().Name );
            throw ex;
        }
    }
}

我当前的两个实现:

public class SqlDataProvider : DataProvider<SqlConnection, SqlCommand, SqlParameter> {
    public SqlDataProvider ( string connstr ) : base( connstr ) { }

    public DataTable ExecuteStoredProcedure(string text, params SqlParameter[] parms ) {
        var dt = new DataTable();
        dt.Load( ExecuteReader( text , CommandType.StoredProcedure , parms ) );
        return dt;
    }

    public DataTable ExecuteStatement(string text, params SqlParameter[] parms ) {
        var dt = new DataTable();
        dt.Load( ExecuteReader( text , CommandType.Text , parms ) );
        return dt;
    }
}

public class OleDataProvider : DataProvider<OleDbConnection, OleDbCommand, OleDbParameter> {
    public OleDataProvider ( string connstr ) : base( connstr ) { }

    public DataTable ExecuteStoredProcedure(string text, params OleDbParameter[] parms ) {
        var dt = new DataTable();
        dt.Load( ExecuteReader( text , CommandType.StoredProcedure , parms ) );
        return dt;
    }

    public DataTable ExecuteStatement(string text, params OleDbParameter[] parms ) {
        var dt = new DataTable();
        dt.Load( ExecuteReader( text , CommandType.Text , parms ) );
        return dt;
    }
}

最终,我正在尝试设置一个框架,以便将来扩展到源自Db*对象族的其他数据库对象。

当前产品跨越与MS-SQL,Sybase,Informatica和Oracle的连接。我知道OleDb可以执行所有4种系统类型的操作,但是如果可用的话,它们可以提供专门的对象结构的能力。

问题

  1. 在实体框架之外是否有更好的方法?
  2. 我是否重复现有的工作(在EF和/或ADO之外)

1 个答案:

答案 0 :(得分:1)

您需要的唯一类型是连接类型。该连接提供了创建后续对象的所有方法。

示例:

using(var connection = new TConnection())
{
    using(var command = connection.CreateCommand())
    {
        var parameter = command.CreateParameter();
        parameter.ParameterName = "@answer";
        parameter.Value = 42;

        command.Parameters.Add(parameter);

        /// and so forth
    }
}

你甚至可以从实际的泛型中移动它......这是运行时行为。您只需要采用IDbConnection的方法,而您的基本方法都不需要知道谁创建了该连接,以及它是SqlConnectionOracleConnection还是其他任何连接。

void MyAgnosticDatabaseMethod(IDbConnection connection)
{
    using(var command = connection.CreateCommand())
    {
        var parameter = command.CreateParameter();
        parameter.ParameterName = "@answer";
        parameter.Value = 42;

        command.Parameters.Add(parameter);

        /// and so forth
    }
}

然后:

using(var connection = new OracleConnection())
{
    MyAgnosticDatabaseMethod(connection);
}

using(var connection = new SqlConnection())
{
    MyAgnosticDatabaseMethod(connection);
}