数据库助手类的C#设计模式
我正在设计一个WCF服务,它将被数百个客户机调用,我有一个关于数据库查询运行的类的最佳体系结构的问题。今天,我只访问SQL Server,所以我有一个静态类,我在内部调用它来完成创建连接和数据读取器的所有脏活。下面是一个简单的例子:数据库助手类的C#设计模式,c#,design-patterns,C#,Design Patterns,我正在设计一个WCF服务,它将被数百个客户机调用,我有一个关于数据库查询运行的类的最佳体系结构的问题。今天,我只访问SQL Server,所以我有一个静态类,我在内部调用它来完成创建连接和数据读取器的所有脏活。下面是一个简单的例子: namespace DBHelper.Utility { public static class SqlDBManager { public static void RunSql(String pSql, DBParamsHelper pDBPara
namespace DBHelper.Utility
{
public static class SqlDBManager
{
public static void RunSql(String pSql, DBParamsHelper pDBParams, String pConnStringConfigName)
{
String sConnectionString = GetConnectionStringFromConfig(pConnStringConfigName);
SqlConnection oConn = new SqlConnectionsConnectionString
oConn.Open();
try
{
SqlCommand oCommand = new SqlCommand(pSql, oConn);
oCommand.CommandTimeout = 0;
if (pDBManagerParams != null)
{
foreach (SqlParameter sqlParam in pDBManagerParams)
{
oCommand.Parameters.Add(sqlParam);
}
}
oCommand.ExecuteNonQuery();
}
finally
{
oConn.Close();
}
}
}
}
现在,我需要添加对运行Sql Server和Oracle的支持。我最初的想法是声明一个接口,让我现有的SqlDBManager
实现它,然后开发一个oracledmanager
实现相同的接口。问题是我的类是静态的,静态类不能实现接口。我希望我的helper类保持静态,因为它更实用,并且我不必每次需要运行查询时都创建一个新对象。我也想过使用类继承,但是我不能使用statis虚拟方法,所以在那里没有太多的用途。我考虑了一些单例实现,这样我就不必创建类,但这样我在多线程访问方面就会遇到问题。最好的设计模式是什么,这样我就可以在多线程场景中获得出色的性能(非常重要),不需要太多的工作来提高效率(不需要创建大量的类),并且对于
OracleDBManager
和SqlDBManager
类都有一个标准方法?标准方法非常重要,因为我不想让使用这些助手类的代码知道它们是否连接到Oracle或Sql Server。我确实考虑过使用ORM解决方案,如实体框架4和NHiBiNATE,但是性能的影响太大。由于我将运行简单的查询,PL-SQL和TSQL之间的查询语法差异并不重要。
任何意见和想法都将不胜感激。Tks为什么不将静态方法设置为私有方法,将类封装在支持MS-SQL/Oracle的接口中,并在相应的接口中调用私有静态方法 例如: 对另一个实现(OracleDbManager)执行相同的操作 将其私有化是有意义的,因为消费者不应该关心底层持久性机制如何工作 这也将使单元测试更容易——创建一个“MockDbManager”类,其中私有静态方法对内存列表执行基本的LINQ操作
另一方面,我强烈建议使用存储过程,而不是手动构造sql命令。查询计划缓存/优化更好。为什么不将静态方法设置为私有方法,将类封装在接口中以支持MS-SQL/Oracle,并在相应的接口中调用私有静态方法 例如: 对另一个实现(OracleDbManager)执行相同的操作 将其私有化是有意义的,因为消费者不应该关心底层持久性机制如何工作 这也将使单元测试更容易——创建一个“MockDbManager”类,其中私有静态方法对内存列表执行基本的LINQ操作
另一方面,我强烈建议使用存储过程,而不是手动构造sql命令。查询计划缓存/优化更好。接口是正确的方向,但正如您所指出的,您不能让静态类实现接口。我知道我想尽量减少对象创建的麻烦,但为了拥有两个不同的数据库类,这在某种程度上可能是必要的 我建议的解决方案是多方面的。首先是一个具有类似于上面所列签名的接口:
public Interface IDbManager {
void RunSql(String pSql, DBParamsHelper pDBParams, String pConnStringConfigName)
}
这可以在SQL和Oracle特定版本中实现,您已经有了SQL版本,只需将其设置为非静态并实现接口即可
现在,请尝试数据库工厂,可能如下所示:
public static class DbFactory {
public static IDbManager CreateDb(DbType type) {
select (type) {
case DbType.Sql:
return new SqlDbManager();
break;
case DbType.Sql:
return new OracleDbManager();
break;
}
}
}
然后,您应该能够执行以下操作:
var db = DbFactory.CreateDb(DbType.Sql);
db.RunQuery(...);
这段代码未经测试,但希望您能理解。我在我的一个项目中使用了类似的解决方案,我需要从不同的数据存储中获取数据。战略和工厂模式简化了这一过程
希望有帮助 接口是正确的方向,但正如您所指出的,不能让静态类实现接口。我知道我想尽量减少对象创建的麻烦,但为了拥有两个不同的数据库类,这在某种程度上可能是必要的 我建议的解决方案是多方面的。首先是一个具有类似于上面所列签名的接口:
public Interface IDbManager {
void RunSql(String pSql, DBParamsHelper pDBParams, String pConnStringConfigName)
}
这可以在SQL和Oracle特定版本中实现,您已经有了SQL版本,只需将其设置为非静态并实现接口即可
现在,请尝试数据库工厂,可能如下所示:
public static class DbFactory {
public static IDbManager CreateDb(DbType type) {
select (type) {
case DbType.Sql:
return new SqlDbManager();
break;
case DbType.Sql:
return new OracleDbManager();
break;
}
}
}
然后,您应该能够执行以下操作:
var db = DbFactory.CreateDb(DbType.Sql);
db.RunQuery(...);
这段代码未经测试,但希望您能理解。我在我的一个项目中使用了类似的解决方案,我需要从不同的数据存储中获取数据。战略和工厂模式简化了这一过程
希望有帮助 我完全同意procs的建议。但是,我需要为每个业务对象重复数据库代码,对吗?@Pascal-correct。怎么了?每个对象的一组CRUD进程。这样你就可以把它们分开。ATM每个对象都使用一种方法。@RPM194现在我明白你的意思了。。但是我的类是帮助类,它们集中了那些无聊的东西来实际运行过程/查询。我真的很感谢你的意见,以及你为你的建议投入的时间,这是一个好主意,但它不符合我目前的需要。但是谢谢你。我完全同意procs的建议。但是,我需要为每个业务对象重复数据库代码,对吗?@Pascal-corre