C#数据库助手类的设计模式

时间:2011-02-24 23:19:45

标签: c# design-patterns

我正在设计一个将由数百个客户端调用的WCF服务,并且我对将由数据库查询运行的类的最佳体系结构有疑问。今天我只访问SQL Server,所以我有一个静态类,我在内部调用它来完成创建连接和数据区域的所有脏工作。以下是一个简单的例子:

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实现它,然后开发一个实现相同接口的OracleDBManager。问题是我的类是静态的,静态类不能实现接口。我希望我的助手类保持静态,它更实用,而且每次我需要运行查询时都不必创建新对象。我还想过使用类继承,但是我不能使用statis虚方法,因此在那里使用不多。我考虑过一些单例实现,所以我不必创建类,但是我会在多线程访问上遇到麻烦 什么是最好的设计模式,所以我可以在多线程场景(非常重要)上有很好的性能,没有太多工作编码生产力(不必创建很多类),并且有{{1的标准方法}和OracleDBManager类?标准方法非常重要,因为我不希望使用这些帮助程序类的代码知道它们是否连接到Oracle或Sql Server。 我确实考虑过使用ORM解决方案,例如Entity Framework 4和nHibernate,但性能影响太大了。由于我将运行简单查询,因此PL-SQL和TSQL之间的查询语法差别无关紧要 任何意见和想法将不胜感激。 TKS

2 个答案:

答案 0 :(得分:2)

为什么不将静态方法私有,在接口中包装类以支持MS-SQL / Oracle,并在相应的接口中调用私有静态方法?

E.g:

public interface ISqlDbManager
{
   void SaveOrder(Order o);
   void FindOrderById(int orderId);
}

public class SqlServerDbManager : ISqlDbManager
{
    private static void RunSql(String pSql, DBParamsHelper pDBParams, String   pConnStringConfigName)
    {
       // implement as you did above
    }

   public void FindOrderById(int orderId)
   {
      // create SQL, call private "RunSql" method.
   }
}

对其他实现(OracleDbManager)执行相同的操作。

将其设置为私有是有道理的,因为消费者不应该关心底层持久性机制的工作原理。

这也将使单元测试更容易 - 创建一个“MockDbManager”类,其中私有静态方法在内存列表中执行基本的LINQ操作。

另外,我强烈建议强烈建议使用存储过程,而不是手动构建sql命令。更适合查询计划缓存/优化。

答案 1 :(得分:2)

接口是正确的方向,但正如您所指出的,您不能让静态类实现接口。我理解想尽量减少对象创建的麻烦,但为了拥有两个不同的数据库类,这可能是必要的。

我建议的解决方案是多方面的。首先是一个签名类似于上面列出的签名的界面:

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(...);

此代码未经测试,但希望您明白这一点。我为我的一个项目使用类似的解决方案,我需要从不同的数据存储中获取数据。战略和工厂模式简化了这一过程。

希望有所帮助!