为不同数据库之间的共享功能创建通用/抽象 "DBContext" Class
Creating a generic / abstract "DBContext" Class for shared functionality among different DBs
我正在开发一个 C# 项目,该项目在不同时间从 SQL Server
、ODBC data-sources
和 Oracle Databases
中提取数据。
此时,我已经创建了 3 个不同的 classes - 每种类型的数据库访问一次。但是,我看到每个库之间 95% 的代码是相同的——主要区别在于创建 Connection
和 Command
对象。
作为 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 数据,并且这样做的方法几乎相同,区别在于 Connection
和 Command
-类型对象。
现在,当我查看两个连接对象时,我发现它们都继承自 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
,方法是创建模拟 DBConnection
和 DBCommand
,然后将其注入您的测试用例。
我喜欢 . 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.
构造函数的实例
然后您可以致电例如CreateCommand
、CreateConnection
或您需要在每个方法中创建的任何其他内容。
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);
我正在开发一个 C# 项目,该项目在不同时间从 SQL Server
、ODBC data-sources
和 Oracle Databases
中提取数据。
此时,我已经创建了 3 个不同的 classes - 每种类型的数据库访问一次。但是,我看到每个库之间 95% 的代码是相同的——主要区别在于创建 Connection
和 Command
对象。
作为 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 数据,并且这样做的方法几乎相同,区别在于 Connection
和 Command
-类型对象。
现在,当我查看两个连接对象时,我发现它们都继承自 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
,方法是创建模拟 DBConnection
和 DBCommand
,然后将其注入您的测试用例。
我喜欢 DbProviderFactory
您 "DB Context" class.
然后您可以致电例如CreateCommand
、CreateConnection
或您需要在每个方法中创建的任何其他内容。
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);