为不同数据库之间的共享功能创建通用/抽象 "DBContext" Class

Creating a generic / abstract "DBContext" Class for shared functionality among different DBs

我正在开发一个 C# 项目,该项目在不同时间从 SQL ServerODBC data-sourcesOracle Databases 中提取数据。

此时,我已经创建了 3 个不同的 classes - 每种类型的数据库访问一次。但是,我看到每个库之间 95% 的代码是相同的——主要区别在于创建 ConnectionCommand 对象。

作为 classes 内容的一个非常简单的例子,这里可以举一个例子:

public class Oracle
{
    static DataTable exec_DT(string query, string conn_str)
    {
        DataTable retVal = new DataTable();

        using (OracleConnection conn = new OracleConnection(conn_str))
            using (OracleCommand cmd = new OracleCommand(query, conn))
            {
                conn.Open();
                using (OracleDataReader rdr = cmd.ExecuteReader())
                {
                    retVal.Load(rdr);
                    rdr.Close();
                }
            }

        return retVal;
    }
}

public class SQLServer
{
    static DataTable exec_DT(string query, string conn_str)
    {
        DataTable retVal = new DataTable();

        using (SqlConnection conn = new SqlConnection(conn_str))
        using (SqlCommand cmd = new SqlCommand(query, conn))
        {
            conn.Open();
            using (SqlDataReader rdr = cmd.ExecuteReader())
            {
                retVal.Load(rdr);
                rdr.Close();
            }
        }

        return retVal;
    }
}

基本上,我需要从我的每个数据库中获取相同类型的 return 数据,并且这样做的方法几乎相同,区别在于 ConnectionCommand-类型对象。

现在,当我查看两个连接对象时,我发现它们都继承自 DbConnection:

public sealed class SqlConnection : DbConnection, ICloneable

public sealed class OracleConnection : DbConnection, ICloneable

但我仍然想不出创建通用/抽象父级的好方法 class 可以停止像 DBConnection / DBCommand classes 这样的代码重复是抽象的,当我尝试以下几行时:

using (DbConnection conn = new DbConnection(conn_str))
using (DbCommand cmd = new DbCommand(query, conn))

我收到诸如 Cannot create an instance of the abstract class or interface 'System.Data.Common.DbCommand'

之类的错误

我是一个新手,任何帮助/示例代码/过去做得很好的方式的链接都会非常感激不尽!

谢谢!!!

这里的关键是退一步,换个角度思考问题。您正在复制大量代码,因为您正在方法中创建数据库和命令 类 的实例。所以注入它们:

public class SomeDBClass
{
    static DataTable exec_DT(DBConnection conn, DBCommand cmd)
    {
        DataTable retVal = new DataTable();
        conn.Open();
        using (SqlDataReader rdr = cmd.ExecuteReader())
        {
            retVal.Load(rdr);
            rdr.Close();
        }
        return retVal;
    }
}

这种方法具有附加值,您可以在不需要 SQLServer 或 Oracle 的情况下测试 exec_DT,方法是创建模拟 DBConnectionDBCommand,然后将其注入您的测试用例。

我喜欢 . In the alternative, if you do still want to be creating connections and commands from within your shared code, what you could do is pass a DbProviderFactory 您 "DB Context" class.

构造函数的实例

然后您可以致电例如CreateCommandCreateConnection 或您需要在每个方法中创建的任何其他内容。

DbProviderFactory class 完全符合您的要求。

static DataTable exec_DT(string query, string conn_str)
{
    DataTable retVal = new DataTable();

    using (DbConnection conn = MyDbProvider.CreateConnection())
    {
        conn.ConnectionString = conn_str;

        using (DbCommand cmd = conn.CreateCommand())
        {
            cmd.CommandText = query;
            conn.Open();

            using (DbDataReader rdr = cmd.ExecuteReader())
            {
                retVal.Load(rdr);
                rdr.Close();
            }
        }
    }

    return retVal;
}

您甚至可以使用 DbProviderFactories class 从配置文件中的连接字符串创建工厂实例。

DbProviderFactories.GetFactory(WebConfigurationManager
    .ConnectionStrings[name].ProviderName);