You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

非EF环境下多数据提供者抽象方案优化及重复实现咨询

问题分析与解决方案

你当前的目标是搭建一个可扩展的异构数据库访问框架,基于System.Data.Common抽象类封装通用逻辑,同时支持专用数据库对象(而非仅依赖OleDb)。先来看你现有的实现代码:

现有基类实现

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; 
        } 
    } 
}

现有实现类

SqlDataProvider

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; 
    } 
}

OleDataProvider

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; 
    } 
}

你的疑问解答

1. 你是否重复了已有工作?

是的,其实ADO.NET原生就提供了DbProviderFactory机制,专门解决异构数据库的统一访问问题,完全可以替代你当前的泛型基类实现。你现在的方案虽然能运行,但每次新增数据库(比如Oracle、Sybase)都需要手动创建新的继承类,而DbProviderFactory可以通过配置驱动的方式动态创建对应的DbConnection、DbCommand、DbParameter等对象,不需要重复编写相似的实现类。

2. 除EF外的更优实现方案

推荐以下两种方向,都比你当前的泛型基类更灵活、更符合ADO.NET的设计规范:

方案一:基于DbProviderFactory封装通用数据访问层

DbProviderFactory是ADO.NET的原生抽象,它可以通过数据库驱动的名称(比如System.Data.SqlClient、Oracle.DataAccess.Client)动态创建所有Db*系列对象。你可以封装一个通用的DataAccess类,所有操作都基于抽象类而非具体实现:

public class GenericDataAccess : IDisposable
{
    private readonly DbProviderFactory _factory;
    private readonly string _connectionString;

    public GenericDataAccess(string providerName, string connectionString)
    {
        _factory = DbProviderFactories.GetFactory(providerName);
        _connectionString = connectionString;
    }

    public DataTable ExecuteDataTable(string commandText, CommandType commandType, params DbParameter[] parameters)
    {
        var dt = new DataTable();
        using (var conn = _factory.CreateConnection())
        {
            conn.ConnectionString = _connectionString;
            conn.Open();
            using (var cmd = _factory.CreateCommand())
            {
                cmd.Connection = conn;
                cmd.CommandText = commandText;
                cmd.CommandType = commandType;
                if (parameters != null)
                {
                    cmd.Parameters.AddRange(parameters);
                }
                using (var reader = cmd.ExecuteReader())
                {
                    dt.Load(reader);
                }
            }
        }
        return dt;
    }

    // 可以扩展更多通用方法:ExecuteScalar、ExecuteNonQuery等

    public void Dispose()
    {
        // 清理资源(如果需要)
    }
}

使用时只需要传入对应的驱动名称和连接字符串:

// SQL Server
var sqlAccess = new GenericDataAccess("System.Data.SqlClient", "your-sql-connection-string");
var sqlDt = sqlAccess.ExecuteDataTable("GetUser", CommandType.StoredProcedure, new SqlParameter("@UserId", 1));

// Oracle
var oracleAccess = new GenericDataAccess("Oracle.DataAccess.Client", "your-oracle-connection-string");
var oracleDt = oracleAccess.ExecuteDataTable("GET_USER", CommandType.StoredProcedure, new OracleParameter("P_USER_ID", 1));

这种方案的优势:

  • 新增数据库只需添加对应的驱动包(比如Oracle.DataAccess、Sybase.Data.AseClient),并在配置文件中注册驱动(或直接传入providerName),无需编写新的实现类
  • 所有数据库操作逻辑复用同一套代码,避免重复
  • 完全基于ADO.NET原生抽象,稳定性和兼容性更好

方案二:结合轻量ORM(如Dapper)

如果你不想自己封装底层的Db*操作,可以使用Dapper——这是一个轻量级ORM,基于ADO.NET实现,性能接近原生ADO.NET,同时提供了对象映射能力。Dapper完全支持DbConnection抽象,所以可以和DbProviderFactory结合使用,快速实现通用数据访问:

public class DapperDataAccess : IDisposable
{
    private readonly DbProviderFactory _factory;
    private readonly string _connectionString;

    public DapperDataAccess(string providerName, string connectionString)
    {
        _factory = DbProviderFactories.GetFactory(providerName);
        _connectionString = connectionString;
    }

    public IEnumerable<T> Query<T>(string sql, object parameters = null, CommandType commandType = CommandType.Text)
    {
        using (var conn = _factory.CreateConnection())
        {
            conn.ConnectionString = _connectionString;
            conn.Open();
            return conn.Query<T>(sql, parameters, commandType: commandType);
        }
    }

    // 扩展更多Dapper方法:Execute、QueryFirstOrDefault等
}

Dapper的优势是减少了手动处理DataTable和对象映射的代码,同时保持了原生ADO.NET的性能,适合需要快速开发又不想引入EF这类重型ORM的场景。


总结

  • 你当前的泛型基类方案存在重复造轮子的问题,ADO.NET原生的DbProviderFactory已经完美解决了异构数据库的统一访问需求
  • 优先推荐基于DbProviderFactory封装通用数据访问层,或者结合Dapper这类轻量ORM,两者都比你当前的方案更灵活、更易扩展
  • 对于你提到的MS-SQL、Sybase、Informatica、Oracle,都有对应的官方或第三方DbProviderFactory驱动支持,无需依赖OleDb

内容的提问来源于stack exchange,提问作者GoldBishop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:52:57