【问题标题】:Data Access Layer design : Different providers same tables and singleton数据访问层设计:不同的提供者相同的表和单例
【发布时间】:2012-11-02 21:08:24
【问题描述】:

我需要构建一个数据访问库,以便以后在许多小型应用程序中使用。

它将大量使用 DataReader 对象。 SQL Server 或 DB2/400 中的表可能具有相同的结构。这意味着例如一个方法

GetItemsByWarehouse()

必须能够针对 SQL Server DB 或 DB2 运行。它将在哪里运行取决于服务器可用性和用户选择。

我打算做什么(并且需要建议)是:

  1. 实施基于单例设计模式的 DAL,以确保我的库只有一个实例。
  2. 有一个可以设置连接字符串的属性。
  3. 如果目标服务器是 AS400 或 SQL,则具有将设置的属性。

我不知道这种做法是否正确。我应该实现第 3 点还是可以从连接字符串中获取类型?

另外我应该如何实现上述方法?检查属性并在方法内部决定我是使用Sqlconnection 还是OleDbConnection e.t.c?

【问题讨论】:

  • 更好的是,我建议您选择一个您喜欢的微型 Orm,然后添加 DB2 支持。它的代码更少,你会开发得更快,因为你已经有一个如何做到这一点的例子
  • 我只是想锻炼自己手动使用设计模式和原则。毕竟应用程序的大小并不能证明 orm 的合理性。在我深入研究 ORM(很可能是 EF)之前,我想有一个相当好的理解。
  • 微型 ORM(基本上是 Ado.Net 之上的一组助手)和像 NHibernate 或 Ef 这样的 ORM 之间存在差异,它们非常复杂,具有许多旨在完全抽象 RDBMS 的特性使用权。 AFAIK EF 不支持 DB2,如果您只是想要一种简单的方法来访问 db,但仍然需要将 SQL 语句直接发送到 db,请使用 micro。 IMO 在极少数情况下使用真正的 ORM 是有意义的。

标签: c# database design-patterns data-access-layer


【解决方案1】:

我从我的 micro Orm 粘贴此代码。构造函数有多个重载来指定要使用的 Db。

 public class DbAccess : IDisposable
{
    public DbAccess()
    {
        var cnx=ConfigurationManager.ConnectionStrings[0];
        if (cnx==null) throw new InvalidOperationException("I need a connection!!!");

        Init(cnx.ConnectionString,ProviderFactory.GetProviderByName(cnx.ProviderName));
    }

    public DbAccess(string connectionStringName)
    {
        var cnx = ConfigurationManager.ConnectionStrings[connectionStringName];
        if (cnx == null) throw new InvalidOperationException("I need a connection!!!");

        Init(cnx.ConnectionString, ProviderFactory.GetProviderByName(cnx.ProviderName));
    }

    public DbAccess(string cnxString,string provider)
    {
        Init(cnxString,ProviderFactory.GetProviderByName(provider));
    }

    public DbAccess(string cnxString,DBType provider)
    {
      Init(cnxString,ProviderFactory.GetProvider(provider));
    }

    public DbAccess(string cnxString,IHaveDbProvider provider)
    {
        Init(cnxString, provider);
    } //other stuff
   }

请注意,DAO (DbAccess) 并不关心具体的提供者。 这是 ProviderFactory 的外观。在这里您可以添加一个方法来检测 db 并返回一个提供程序。

   internal static class ProviderFactory
{
    public static IHaveDbProvider GetProviderByName(string providerName)
    {
        switch (providerName)
        {
            case SqlServerProvider.ProviderName:return new SqlServerProvider();
            case MySqlProvider.ProviderName:return new MySqlProvider();
            case PostgresProvider.ProviderName:return new PostgresProvider();
            case OracleProvider.ProviderName:return new OracleProvider();
            case SqlServerCEProvider.ProviderName:return new SqlServerCEProvider();
            case SqliteProvider.ProviderName:return new SqliteProvider();
        }
        throw new Exception("Unkown provider");
    }

    public static IHaveDbProvider GetProvider(DBType type)
    {
        switch (type)
        {
            case DBType.SqlServer: return new SqlServerProvider();
            case DBType.SqlServerCE: return new SqlServerCEProvider();
            case DBType.MySql: return new MySqlProvider();
            case DBType.PostgreSQL:return new PostgresProvider();
            case DBType.Oracle:return new OracleProvider();
            case DBType.SQLite:return new SqliteProvider();
        }
        throw new Exception("Unkown provider");
    }
}

更多代码sn-ps和灵感可以查看Github repo

我建议不要使用单例模式,让 DI 容器管理实例生命周期要好得多。此外,应用程序应该使用 DAO 的接口而不是具体实例(这将在未来帮助您)。

【讨论】:

    【解决方案2】:

    看看Abstract Factory Pattern

    您可以拥有一个与 DAL 合同的接口以及每个上下文的实现。使用工厂,它可以决定在每种情况下使用哪个实现。工厂将需要“切换规则”来决定使用什么。

    【讨论】:

    • 所以你是说我不会有一个方法的实现?这里的诀窍是查询和结果是相同的,但有一次我可能使用的是 SQL 服务器和另一个 AS400。抽象工厂必须决定调用哪个方法。如果我想对两者都使用一种方法怎么办?或者这不是一个好习惯?
    • 不,您将有两个实现相同的方法。您的实现(SQL 和 AS400)将填充界面。当抽象工厂决定使用哪个实现(取决于用户偏好或其他)时,调用类(使用接口)将不知道实现。这样,您将封装 DAL,并使其面向接口。
    • 好的,我认为将抽象工厂与单例结合起来会给我想要的结果。但是,如果我不必区分 2 个底层数据提供程序并且我只想在多个 SQL Server 之间进行选择,我只需要为连接字符串实现一个属性?当然仍然应用单例设计。
    猜你喜欢
    • 1970-01-01
    • 2014-01-09
    • 2013-01-08
    • 1970-01-01
    • 1970-01-01
    • 2011-06-18
    • 1970-01-01
    • 2021-03-23
    • 2014-11-12
    相关资源
    最近更新 更多