ASP.NET MVC4+EF系列之六仓储实现 IRepository 和 Repository
名词介绍:首先我们必须了解一点领域驱动(DDD)相关知识,至少要对一些名词熟悉,我上传的源代码的注释包含了很多这些名词。例如仓储,仓储上下文,仓储根,领域对象,以及什么领域对象可以考虑作为仓储根。这里我就按我的理解做个粗浅的介绍。不当之处请原谅。比较DDD不是一朝一夕能领悟的东西,需要理论加实践的不断磨合,我这里只是简单的DDD。
1.领域对象:就是我们业务中的一个个对象。我想这不用多加解释了。
2.仓储根:就是能被直接操作到数据库的领域对象,它是领域对象的子集。业务当中的所有操作都是对仓储根的操作。也只有仓储根能被放进仓储,让后被固化到数据库。在不同的业务中仓储根是不同的,利于在订单中订单对象肯定就是仓储根,但是订单地址就不是,订单地址只是作为订单的属性而存在。我们框架中通过这个TAggregateRoot借口去
3.仓储:其实就是领域对象存放的地方。每一个领域对象都有自己的仓储。这里面存储了很多同一类型的对象
4.仓储上下文:不通仓储存放的地方,对不通仓储根的仓储进行管理。
更多的名词我就不一一介绍,我只介绍我用的比较多的。更多领域驱动相关,推荐大家网上学习了解下
一.IRepository 和 Repositor概述
Repository顾名思义就是仓储,Repository继承了IRepository接口,并且实现了一套通用的操作仓储根的方法,通过这些方法我们可以很灵活的操作数据库。Repository只是基础的仓储。至于具体的通过EF还是NH去实现数据的固化和查询。我们主要继承Repository这个类就行了。Repository是一个抽象类。只能被继承。让后去实现各种具体的仓储,是用EF还是用NH操作数据那就取决于我们了。IRepository为仓储提供了一套标准。我么这里选择了EF,这种后面详述。
1.IRepository基本仓储标准
1 /***************************************************** 2 * 作者:egojit 3 * 日期:2012-7-13 4 * 描述:仓储接口 5 * ***************************************************/ 6 using System; 7 using System.Collections.Generic; 8 using System.Linq.Expressions; 9 using EgojitFramework.Domain.Specifications; 10 11 12 namespace EgojitFramework.Domain.Repositories 13 { 14 /// <summary> 15 /// 仓储接口 16 /// </summary> 17 /// <typeparam name="TAggregateRoot">仓储根类型</typeparam> 18 public interface IRepository<TAggregateRoot> 19 where TAggregateRoot : class, IAggregateRoot 20 { 21 /// <summary> 22 ///获取仓储上下文实例 23 /// </summary> 24 IRepositoryContext Context { get; } 25 /// <summary> 26 /// 添加一个仓储根到仓储中 27 /// </summary> 28 /// <param name="aggregateRoot">仓储根.</param> 29 void Add(TAggregateRoot aggregateRoot); 30 /// <summary> 31 /// 通过Key从仓储中获取仓储根实例 32 /// </summary> 33 /// <param name="key">key.</param> 34 /// <returns>仓储根实例</returns> 35 TAggregateRoot GetByKey(Guid key); 36 /// <summary> 37 /// 从仓储中获取所有的仓储根实例 38 /// </summary> 39 /// <returns>仓储根实例列表</returns> 40 IEnumerable<TAggregateRoot> GetAll(); 41 /// <summary> 42 /// 分页从仓储中获取所有的仓储根实例 43 /// </summary> 44 /// <param name="pageNumber">页号</param> 45 /// <param name="pageSize">每页的数量</param> 46 /// <returns>指定页的仓储根列表</returns> 47 IEnumerable<TAggregateRoot> GetAll(int pageNumber, int pageSize); 48 /// <summary> 49 /// 从仓储中获取所有的仓储根实例并且排序 50 /// </summary> 51 /// <param name="sortPredicate">The sort predicate which is used for sorting.</param> 52 /// <param name="sortOrder">The <see cref="Apworks.SortOrder"/> enumeration which specifies the sort order.</param> 53 /// <returns>All the aggregate roots got from the repository, with the aggregate roots being sorted by 54 /// using the provided sort predicate and the sort order.</returns> 55 IEnumerable<TAggregateRoot> GetAll(Expression<Func<TAggregateRoot, dynamic>> sortPredicate, SortOrder sortOrder); 56 /// <summary> 57 /// 分页从仓储中获取所有的仓储根实例并且排序 58 /// </summary> 59 /// <param name="sortPredicate">排序条件</param> 60 /// <param name="sortOrder">排序方式</param> 61 /// <param name="pageNumber">页号</param> 62 /// <param name="pageSize">每页数量</param> 63 /// <returns>排序后的仓储根列表</returns> 64 IEnumerable<TAggregateRoot> GetAll(Expression<Func<TAggregateRoot, dynamic>> sortPredicate, SortOrder sortOrder, int pageNumber, int pageSize); 65 } 66 }
当然这个接口中远不止这么多代码。更多请参照源码。从
/// <summary> /// 仓储接口 /// </summary> /// <typeparam name="TAggregateRoot">仓储根类型</typeparam> public interface IRepository<TAggregateRoot> where TAggregateRoot : class, IAggregateRoot
这行代码我们很容易看出来IRepository类中的操作的对象都是基础自TAggregateRoot接口的仓储根,这就很好的限制了普通实体的数据库操作。
2.继承自IRepository接口的Repository仓储类
部分代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using EgojitFramework.Domain.Specifications; using System.Linq.Expressions; /***************************************************** * 作者:egojit * 日期:2012-7-13 * 描述:仓储抽象类 * ***************************************************/ namespace EgojitFramework.Domain.Repositories { /// <summary> /// 仓储基础类 /// </summary> /// <typeparam name="TAggregateRoot">The type of the aggregate root on which the repository operations /// should be performed.</typeparam> public abstract class Repository<TAggregateRoot> : IRepository<TAggregateRoot> where TAggregateRoot : class, IAggregateRoot { #region 私有字段 private readonly IRepositoryContext context; #endregion #region 属性 /// <summary> /// 仓储上下文的一个实例 /// </summary> /// <param name="context">被这个仓储使用的仓储上下文</param> public Repository(IRepositoryContext context) { this.context = context; } #endregion #region 私有方法 /// <summary> /// 添加一个仓储根到仓储 /// </summary> /// <param name="aggregateRoot">被添加的仓储根</param> protected abstract void DoAdd(TAggregateRoot aggregateRoot); /// <summary> /// 通过Key在这个仓储中获取仓储根 /// </summary> /// <param name="key">Key</param> /// <returns>仓储实例</returns> protected abstract TAggregateRoot DoGetByKey(Guid key); 。。。。。。此次省去更多代码 } }
通过代码我们很容易知道它操作的也是仓储根,并且继承了IRepository接口,而且它是抽象的,必须被继承去实现,这样我们就为基于EF或者是NH或者其它实现的仓储提供了一种很容易的途径,只要在他的子类中去重现其中的方法就行了。我们看到通过构造函数将仓储上下文带到了这个类中。
这节就介绍这个基本仓储,下个节。将介绍仓储中的事务管理。(次阶段源代码下载)
版权:归博客园和egojit共同所有,转载请标明出处