应用程序框架实战二十一:DDD分层架构之仓储(介绍篇)

  前面已经介绍过Entity Framework的工做单元和映射层超类型的封装,从本文开始,将逐步介绍仓储以及对查询的扩展支持。程序员

什么是仓储                                                  

  仓储表示聚合的集合。数据库

  仓储所表现出来的集合外观,仅仅是一种模拟,除了测试之外,没有理由使用内存中真正的集合来建立仓储。安全

  不该该为全部实体创建仓储,只有聚合才拥有仓储。框架

  仓储用来重建已持久化的聚合,而工厂用于新建聚合。性能

使用仓储的优势                                                  

  直接使用Entity Framework的DbContext不是很好吗,为何还要在DbContext的上方封装一层仓储呢,这是否画蛇添足?单元测试

  不少使用EF的程序员确实是直接使用DbContext,而且他们发现开发起来十分简单,由于DbContext的接口设计得很是优雅,从接口上看,DbContext就好像全部实体集合的仓库。测试

  另外一方面,不少使用了仓储的朋友,都是依葫芦画瓢,虽然建立了仓储,但并无体会到多大好处。spa

  下面简要介绍使用仓储将为你带来的优势。设计

从概念上简化数据操做

  仓储模拟了某种聚合的集合,而DbContext包含了N种类型的集合。对象

  与仓储相近的一个数据访问模式是数据访问对象(DAO)模式,不少人认为仓储不过是数据访问对象换了一个名词而已,从技术上说的确如此,仓储的强大之处在于概念上更简单。仓储在概念上表明内存中的集合操做,而数据访问对象表明数据库操做,很明显,集合比数据库在概念上更简单。

减小冗余查询逻辑

  若是直接使用DbContext,因为特定查询逻辑没有一个固定位置,可能分散到任何地方,这很容易形成冗余。

  仓储是封装特定查询逻辑的好地方,对于特定的查询逻辑,放到与聚合相应的仓储中便可。

下降耦合度

  直接使用DbContext,全部调用代码与EF实现高度耦合。

  另外一方面,因为DbContext可以获取任意实体,这些实体可能位于聚合内部,这样会破坏聚合的封装性,同时在任意位置能够获取任意对象,因为缺少约束力而致使更高的耦合。

方便单元测试

  直接使用DbContext只能进行集成测试,必须链接到真实数据库。而领域层只持有仓储接口,因此测试时很容易替换成模拟实现,从而避开数据库。

使用仓储的要点                                                  

使用更具体的仓储

  通常来说,ICustomerRepository比直接使用泛型的IRepository<Customer>要好。

  为了定义通用操做,咱们会建立一些泛型基类来实现基础操做。

  有些人发现不少具体仓储只是直接继承泛型仓储,好比ICustomerRepository和CustomerRepository从泛型的IRepository<Customer>和Repository<Customer>派生,但CustomerRepository自己并无其它什么代码。因而不少人学会偷懒,直接使用泛型基类进行操做。

  ICustomerRepository优于IRepository<Customer>的缘由以下。

  1.  概念上更清晰。

  ICustomerRepository从概念上良好表达了该仓储用于操做客户,而泛型仓储能够操做任何聚合。

  2.  为特定查询逻辑提供惟一封装和访问点。

  ICustomerRepository能够将客户相关的各类复杂查询封装起来,而IRepository<Customer>很难对客户查询进行封装,一个办法是使用扩展方法来完成封装,不过比起CustomerRepository要麻烦得多,并且实现代码也更难管理。

  3.  下降耦合。

  泛型IRepository<>能够在任意位置获取任意聚合,这比起DbContext要强一些,不会破坏聚合的封装性,但缺少约束力仍然会致使更高耦合。

  ICustomerRepository经过明确的声明,只能获取须要的聚合,从而控制了对象的访问。

仓储仅返回与其聚合高度相关的内容

  仓储能够返回对应的聚合,也能够返回聚合相关的统计信息,甚至能够返回聚合的一个子集。

  有人在仓储查询中使用匿名对象,使用匿名对象的缘由很简单,即为了进行投影操做,这样能够限制Sql查询返回的列,对于Sql性能调优来说,这可能很是重要,好比使用Sql Server的覆盖索引。

  可是使用匿名对象进行查询有不少问题,一个问题是没法直接做为结果返回。有人为了省力,直接使用聚合或其部分子对象做为返回类型,其结果是对象中的一部分属性被赋值,另外一部分属性为null。这可能致使许多神秘的Bug,另外致使你或其它人对仓储查询信心不足,由于这些查询并不安全,你每当须要调用一个查询,首先得仔细检查代码,看看哪些值是空的,以避免踩到地雷。

  若是要返回聚合的一个子集,须要单独定义一些对象,以做为返回类型。工做量虽然比较大,但更加安全和清晰。

  若是须要获取的内容由多个聚合组成,这个查询操做应该放入哪一个仓储中?这种状况放到哪一个仓储其实都不合适,更好的办法是使用一个查询服务,就好像跨越多个聚合的业务操做须要领域服务同样。

总结                                                  

1. 仓储的定义

  仓储表示聚合的集合。

2. 仓储的优势

  • 简化数据操做
  • 减小冗余查询逻辑
  • 下降耦合度
  • 方便单元测试

3. 仓储的要点

  • 使用更具体的仓储
  • 仓储查询仅返回与其聚合高度相关的内容 

 

 

  因为仓储是对数据操做的封装,包括仓储基础,分页,查询扩展,查询对象,查询条件(规约模式),查询条件应用(日期范围与数值范围查询)等内容,因此须要多篇文章进行介绍。 

  .Net应用程序框架交流QQ群: 386092459,欢迎有兴趣的朋友加入讨论。

  谢谢你们的持续关注,个人博客地址:http://www.cnblogs.com/xiadao521/

相关文章
相关标签/搜索