【问题标题】:Repository Pattern vs DAL存储库模式与 DAL
【发布时间】:2010-09-22 10:11:02
【问题描述】:

它们是一样的吗?刚看完Rob Connery's Storefront tutorial,他们似乎是相似的技术。我的意思是,当我实现一个 DAL 对象时,我有 GetStuff、Add/Delete 等方法,并且我总是先编写接口,以便以后可以切换数据库。

我是不是搞错了?

【问题讨论】:

    标签: asp.net-mvc data-access-layer


    【解决方案1】:

    你绝对不是混淆事物的人。 :-)

    我认为这个问题的答案取决于你想成为多少纯粹主义者。

    如果您想要一个严格的 DDD 观点,那将带您走上一条路。如果您将存储库视为一种模式,它帮助我们标准化了分离服务和数据库的层的接口,它会让您失望。

    从我的角度来看,存储库只是一个明确指定的数据访问层。或者换句话说,一种实现数据访问层的标准化方法。不同的存储库实现之间存在一些差异,但概念是相同的。

    有些人会对存储库施加更多的 DDD 约束,而另一些人会将存储库用作数据库和服务层之间的便捷中介。像 DAL 这样的存储库将服务层与数据访问细节隔离开来。

    似乎使它们不同的一个实现问题是,通常使用采用规范的方法创建存储库。存储库将返回满足该规范的数据。我见过的大多数传统 DAL 将具有一组更大的方法,其中该方法将采用任意数量的参数。虽然这听起来可能是一个很小的差异,但当您进入 Linq 和 Expressions 领域时,这是一个大问题。 我们的默认存储库界面如下所示:

    public interface IRepository : IDisposable
    {
        T[] GetAll<T>();
        T[] GetAll<T>(Expression<Func<T, bool>> filter);
        T GetSingle<T>(Expression<Func<T, bool>> filter);
        T GetSingle<T>(Expression<Func<T, bool>> filter, List<Expression<Func<T, object>>> subSelectors);
        void Delete<T>(T entity);
        void Add<T>(T entity);
        int SaveChanges();
        DbTransaction BeginTransaction();
    }
    

    这是 DAL 还是存储库?在这种情况下,我猜两者兼而有之。

    【讨论】:

    • 迟到了,但为什么是 T[],而不是 List(或类似的)?
    • 也许 IEnumerable 会是最好的。
    • 我认为 IQueryable 将是最佳选择,因为它允许您链接方法并延迟执行,让数据库完成所有工作。
    • 我希望能够将方法链接在一起,但我们所有的逻辑都包含在存储过程中。我将使用这种模式,但没有表达式链接的好处。
    • @kenwarner 我认为返回 IQueryable 会泄漏抽象。您应该从存储库中返回域对象。
    【解决方案2】:

    存储库是一种可以以多种不同方式应用的模式,而数据访问层有一个非常明确的职责:DAL 必须知道如何连接到您的数据存储以执行 CRUD 操作。

    存储库可以是 DAL,但它也可以位于 DAL 前面,充当业务对象层和数据层之间的桥梁。使用哪种实现会因项目而异。

    【讨论】:

      【解决方案3】:

      一个很大的区别是,DAO 是一种处理域中任何实体的持久性的通用方法。另一方面,存储库仅处理聚合根。

      【讨论】:

      • 首先要了解的是,作为模式的存储库是称为域驱动设计的更大系统的一部分。在 DDD 中,域对象被分组为聚合,每个聚合都有一个聚合根。例如。 PurchaseOrder 是聚合根,OrderItems 是聚合根中的子项。存储库仅处理聚合根。也就是说,例如 OrderItem 永远不会独立于它的聚合根加载。因此,您永远不会在 DDD 中拥有 OrderItem 存储库。但是,在非 DDD 系统中,您可以使用 OrderItemDao,因为 Dao 不限于聚合根。
      • NG,谢谢!我已经开始这样看待它,但这说明了这一点。我得开始阅读所有 DDD 文献!
      • @bingle,很好地描述了聚合根以及存储库如何加载子对象。存储库将存在于多层应用程序中的什么位置?我可以看到它位于数据访问层库中,但由于它加载子对​​象,它是否应该存在于逻辑层库中?我的直觉告诉我数据访问层,但我想听听您对此事的看法。
      【解决方案4】:

      我正在寻找类似问题的答案,并同意排名最高的两个答案。试图为自己澄清这一点,我发现 if 规范,与存储库模式齐头并进,被实现为领域模型的一等成员,那么我可以

      • 重用具有不同参数的规范定义,
      • 操纵现有规范实例的参数(例如,专门化),
      • 结合他们,
      • 对它们执行业务逻辑,而无需进行任何数据库访问,
      • 当然,单元测试它们独立于实际的存储库实现。

      我什至可以说除非存储库模式与规范模式一起使用,否则它不是真正的“存储库”,而是一个 DAL。伪代码中的人为示例:

      specification100 = new AccountHasMoreOrdersThan(100)
      specification200 = new AccountHasMoreOrdersThan(200)
      
      assert that specification200.isSpecialCaseOf(specification100)
      
      specificationAge = new AccountIsOlderThan('2000-01-01')
      
      combinedSpec = new CompositeSpecification(
          SpecificationOperator.And, specification200, specificationAge)
      
      for each account in Repository<Account>.GetAllSatisfying(combinedSpec)
          assert that account.Created < '2000-01-01'
          assert that account.Orders.Count > 200
      

      请参阅Fowler's Specification Essay 了解详情(这是我上面的内容)。

      DAL 会有专门的方法,例如

      IoCManager.InstanceFor<IAccountDAO>()
          .GetAccountsWithAtLeastOrdersAndCreatedBefore(200, '2000-01-01')
      

      您可以看到这很快就会变得很麻烦,特别是因为您必须使用这种方法定义每个 DAL/DAO 接口实现 DAL 查询方法。

      在 .NET 中,LINQ 查询可以成为实现规范的一种方式,但组合规范(表达式)可能不像使用本土解决方案那样顺畅。 this SO Question 中描述了一些想法。

      【讨论】:

        【解决方案5】:

        我个人的看法是,这都是关于映射的,请参阅:http://www.martinfowler.com/eaaCatalog/repository.html。所以存储库的输出/输入是域对象,在 DAL 上可以是任何东西。对我来说,这是一个重要的添加/限制,因为您可以为数据库/服务/任何具有不同布局的内容添加存储库实现,并且您有一个明确的位置可以专注于进行映射。如果您不使用该限制并在其他地方进行映射,那么使用不同的方式来表示数据可能会影响不应更改的地方的代码。

        【讨论】:

          【解决方案6】:

          这一切都与解释和上下文有关。它们可能非常相似,也可能确实非常不同,但只要解决方案能胜任,名字里有什么!

          【讨论】:

            【解决方案7】:

            在外部世界(即客户端代码)存储库与 DAL 相同,除了:

            (1) 它的插入/更新/删除方法被限制为以数据容器对象作为参数。

            (2) 对于读取操作,它可能需要简单的规范,如 DAL(例如 GetByPK)或高级规范。

            在内部,它与数据映射层(例如实体框架上下文等)一起执行实际的 CRUD 操作。

            什么存储库模式并不意味着:-

            另外,我看到人们经常感到困惑,除了插入/更新/删除方法之外,还有一个单独的保存方法作为存储库模式示例实现,它将插入/更新/删除方法执行的所有内存更改提交到数据库。我们可以在存储库中肯定有一个 Save 方法,但这不是存储库的责任来隔离内存中 CUD(创建、更新、删除)和持久性方法(在数据库中执行实际的写入/更改操作),但是工作单元模式的责任。

            希望这会有所帮助!

            【讨论】:

              【解决方案8】:

              存储库是一种模式,这是一种以标准化方式实现事物以尽可能重用代码的方式。

              【讨论】:

                【解决方案9】:

                使用存储库模式的优点是模拟您的数据访问层,这样您就可以在不调用 DAL 代码的情况下测试您的业务层代码。还有其他很大的优势,但这对我来说似乎非常重要。

                【讨论】:

                • 您仍然可以模拟 DAL,它本身不需要是存储库。重要的一点是,无论您使用什么数据访问策略,它都应该实现一个接口。这将允许您使用 IoC 容器以及整洁地测试您的业务代码,而无需数据存储。
                【解决方案10】:

                据我了解,它们的含义基本相同 - 但命名因上下文而异。

                例如,您可能有一个实现 IRepository 接口的 Dal/Dao 类。

                Dal/Dao 是一个数据层术语;您的应用程序的较高层会考虑存储库。

                【讨论】:

                  【解决方案11】:

                  那么在大多数(简单)情况下,DAO 是 Repository 的实现?

                  据我了解,DAO 似乎精确处理数据库访问(CRUD - 没有选择?!)而 Repository 允许您抽象整个数据访问,也许是多个 DAO 的外观(可能是不同的数据源)。

                  我走对了吗?

                  【讨论】:

                  • 实际上,我会反过来说,从简单的角度来看,存储库是 DAO 的一种特殊实现方式,但是是的,您走在正确的道路上。 (CRUD 中的 R = 读取,所以这是您的选择。)
                  【解决方案12】:

                  有人可能会争辩说,“存储库”是一个特定的类,而“DAL”是由存储库、DTO、实用程序类和其他任何所需的东西组成的整个层。

                  【讨论】:

                    猜你喜欢
                    • 2012-07-13
                    • 1970-01-01
                    • 2015-08-13
                    • 2023-03-21
                    • 1970-01-01
                    • 2012-09-02
                    • 2023-03-23
                    • 1970-01-01
                    • 2012-08-22
                    相关资源
                    最近更新 更多