【问题标题】:How to design a provider-independent DAL如何设计独立于提供者的 DAL
【发布时间】:2010-10-20 19:39:11
【问题描述】:

我目前正在开发一个查询构建器应用程序,基本上是一个简单的图形界面,应该允许不了解 SQL 的用户在数据库上定义各种查询(连接、SELECT、INSERT、UPDATE、DELETE)。我将使用 .NET 3.5。我的应用程序应该支持多个数据库,它应该与 MS-SQL Server、MySQL 和 Oracle 一起使用,所以我希望能提供任何提示或链接到有关如何设计独立于提供程序的 DAL 的相关讲座。

用户将选择一个数据库服务器,当前服务器上的一个数据库,提供连接凭据,选择各种表,定义查询(使用一系列组合框),最后执行查询(如果它们有效)。当然,在 DAL 中,我确实希望为每个数据库提供程序提供方法。我正在考虑工厂模式的一些内容。

注意:这是一个简单的学校项目,所以我对结果查询的安全性或性能不感兴趣。

更新:经过更多的研究和您提供的非常有价值的意见,我决定使用DbProviderFactory。 ORM 会很有趣,但是因为我只想要一个查询分析器/构建器,所以我看不出使用它的意义。因此,如果您能向我提供有关如何使用 DbProviderFactory 和相关类的详细教程,我将不胜感激。

【问题讨论】:

    标签: .net data-access-layer query-builder provider-independent


    【解决方案1】:

    我建议使用 System.Data.Common.DbProviderFactories 类来生成通用 ADO.NET 类。

    当您找到更多要支持的数据库的 .NET 提供程序时,只需将提供程序 DLL 拖放到应用程序的路径中,并在 app.config 文件中添加对提供程序的 DbProviderFactory 的引用。您可以让用户选择要使用的提供程序。

    这是一篇关于名为 Obtaining a DbProviderFactory (ADO.NET) 的主题的 MSDN 文章

    我以前使用过这种方法,并且能够在同一个项目中支持 MSSQL 和 SQLite,只需稍作配置更改。

    不确定,但它是否也适用于查询构建器应用……

    【讨论】:

    • 这对他有什么帮助?检索适当的 DbProviderFactory 只占 0.2% 的功能,最复杂的部分将是实际的查询语法,而 DbProviderFactory 的功能根本没有涵盖
    • 他没有问任何关于查询语法的问题。他询问了独立于提供商的 DAL。 DbProviderFactory 确实为他提供了一个已经实现的工厂模式,以作为他的 DAL 的基础。缺乏功能是因为它必须能够与广泛的 RDBMS 一起工作,因此不能使用数据库的任何供应商特定的特性。如果他坚持直接选择、更新、删除和插入,应该不会有任何问题。但理所当然,ORM 确实给了你更多。
    • 至于使用 ORM:如果应用程序具有硬编码的业务对象,它将完美地工作。但是,如果应用程序是一个没有特定域的简单查询构建器/运行器(如 MS 的查询分析器),据我所知,ORM 并没有多大帮助。如果我错了,请纠正我。我不是 100% 了解 ORM 的所有用途。
    • “一个简单的图形界面,应该允许不了解 SQL 的用户在数据库上定义各种查询”加上“......如果查询有效,则执行查询。当然,在 DAL我确实想为每个 DB 提供程序提供方法”暗示需要查询语法。
    • 好的,我明白你的意思了。看起来我误解了这个问题。
    【解决方案2】:

    我必须说,在视觉上编辑一个相当复杂的查询是非常麻烦的。并且允许用户使用可视化设计器插入/删除数据是一种自取其辱的方式。精简版的 Management Studio、基本 SQL 知识以及受限服务器用户会做得更好。

    如果您仍然倾向于设计此应用程序,您将需要 NHibernate。更准确地说,Criteria Queries 可以完成这项工作,因为它们的映射非常接近您的需要。

    【讨论】:

      【解决方案3】:

      您可能会感到惊讶,但可以使用普通的旧 DataSetDataTable 实现非常简单的独立于提供商的 DAL。

      【讨论】:

        【解决方案4】:

        我认为 ADO.NET Entity Framework(自 .NET 3.5 SP1 起可用)是一个不错的选择,因为它几乎通过其实体 SQL 语言抽象出依赖于数据库的 SQL。

        【讨论】:

        • 目前,ADO.NET EF 仅支持微软的 DBMS。
        • 它的设计本质上是独立于数据库的。我很确定其他 DBMS 也有 EF 提供程序(谷歌它)。我不确定它们的稳定性,因为我还没有使用它们。
        【解决方案5】:

        大多数 ORM(对象关系映射器)都知道如何与各种数据库类型通信。

        至于允许用户构建自己的查询:您需要非常小心。用户可能会创建恶意查询(尽管这可能是一个问题)并不是因为它是偶然的。编写一个使用所有可用服务器资源并为您的数据库创建有效拒绝服务的查询非常容易。

        【讨论】:

          【解决方案6】:

          我不确定这是否有助于您的任务,但我最近学到并牢记的一件事是让您的数据模型的唯一标识符实现不直接传播到数据层之外,而是包装在一个抽象。例如,这是一个包装模型标识符的接口:

          public interface IModelIdentifier<T> where T : class 
          {
              /// <summary>
              /// A string representation of the domain the model originated from.
              /// </summary>
              string Origin { get; }
          
              /// <summary>
              /// The model instance identifier for the model object that this 
              /// <see cref="IModelIdentifier{T}"/> refers to.  Typically, this 
              /// is a database key, file name, or some other unique identifier.
              /// <typeparam name="KeyDataType">The expected data type of the 
              /// identifier.</typeparam>
              /// </summary>
              KeyDataType GetKey<KeyDataType>();
          
              /// <summary>
              /// Performs an equality check on the two model identifiers and 
              /// returns <c>true</c> if they are equal; otherwise <c>false</c> 
              /// is returned.  All implementations must also override the equal operator.
              /// </summary>
              /// <param name="obj">The identifier to compare against.</param>
              /// <returns><c>true</c> if the identifiers are equal; otherwise 
              /// <c>false</c> is returned.</returns>
              bool Equals(IModelIdentifier<T> obj);
          }
          

          您的业务逻辑层过去可能作为唯一标识符传递 ints(例如,来自数据库表中的标识列),现在这样传递:

              public IPerson RetrievePerson(IModelIdentifier<IPerson> personId)
              {
                  /// Retrieval logic here...
              }
          

          然后,您的数据层将有一个实现IModelIdentifier&lt;Person&gt; 并使用物理模型的唯一标识符填充其内部数据类型的类。这使您的业务层免受您在数据层可能进行的任何更改的影响,例如将您的 int 键标识符替换为 Guids。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-05-02
            • 2016-01-31
            • 1970-01-01
            • 2013-03-08
            • 1970-01-01
            • 2015-04-01
            • 1970-01-01
            • 2021-05-11
            相关资源
            最近更新 更多