前言:上篇介绍了下仓储的代码架构示例以及简单分析了仓储了使用优点。本章仍是继续来完善下仓储的设计。上章说了,仓储的最主要做用的分离领域层和具体的技术架构,使得领域层更加专一领域逻辑。那么涉及到具体的实现的时候咱们应该怎么作呢,本章就来讲说仓储里面具体细节方便的知识。html
DDD领域驱动设计初探系列文章:sql
//仓储的泛型实现类 public class EFBaseRepository<TEntity> : IRepository<TEntity> where TEntity : AggregateRoot { [Import(typeof(IEFUnitOfWork))] public IEFUnitOfWork UnitOfWork { get; set; } public EFBaseRepository() { Regisgter.regisgter().ComposeParts(this); } public virtual IQueryable<TEntity> Entities { get { return UnitOfWork.context.Set<TEntity>(); } } public virtual TEntity GetByKey(object key) { return UnitOfWork.context.Set<TEntity>().Find(key); } public virtual IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> express) { Func<TEntity, bool> lamada = express.Compile(); return UnitOfWork.context.Set<TEntity>().Where(lamada).AsQueryable<TEntity>(); } public virtual int Insert(TEntity entity) { UnitOfWork.RegisterNew(entity); return UnitOfWork.Commit(); } public virtual int Insert(IEnumerable<TEntity> entities) { foreach (var obj in entities) { UnitOfWork.RegisterNew(obj); } return UnitOfWork.Commit(); } public virtual int Delete(object id) { var obj = UnitOfWork.context.Set<TEntity>().Find(id); if (obj == null) { return 0; } UnitOfWork.RegisterDeleted(obj); return UnitOfWork.Commit(); } public virtual int Delete(TEntity entity) { UnitOfWork.RegisterDeleted(entity); return UnitOfWork.Commit(); } public virtual int Delete(IEnumerable<TEntity> entities) { foreach (var entity in entities) { UnitOfWork.RegisterDeleted(entity); } return UnitOfWork.Commit(); } public virtual int Delete(Expression<Func<TEntity, bool>> express) { Func<TEntity, bool> lamada = express.Compile(); var lstEntity = UnitOfWork.context.Set<TEntity>().Where(lamada); foreach (var entity in lstEntity) { UnitOfWork.RegisterDeleted(entity); } return UnitOfWork.Commit(); } public virtual int Update(TEntity entity) { UnitOfWork.RegisterModified(entity); return UnitOfWork.Commit(); } }
仓储接口:数据库
public interface IRepository<TEntity> where TEntity : AggregateRoot { //........... #region 公共方法 /// <summary> /// 根据lamada表达式查询集合 /// </summary> /// <param name="selector">lamada表达式</param> /// <returns></returns> IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> express); /// <summary> /// 根据lamada表达式删除对象 /// </summary> /// <param name="selector"> lamada表达式 </param> /// <returns> 操做影响的行数 </returns> int Delete(Expression<Func<TEntity, bool>> express); //.......... }
仓储的实现express
//仓储的泛型实现类 public class EFBaseRepository<TEntity> : IRepository<TEntity> where TEntity : AggregateRoot { //............. public virtual IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> express) { Func<TEntity, bool> lamada = express.Compile(); return UnitOfWork.context.Set<TEntity>().Where(lamada).AsQueryable<TEntity>(); } public virtual int Delete(Expression<Func<TEntity, bool>> express) { Func<TEntity, bool> lamada = express.Compile(); var lstEntity = UnitOfWork.context.Set<TEntity>().Where(lamada); foreach (var entity in lstEntity) { UnitOfWork.RegisterDeleted(entity); } return UnitOfWork.Commit(); } //............. }
增长这两个方法以后,对于单表的通常查询均可以直接经过lamada表示式的方法传入便可,而且返回值为IQueryable类型。架构
在菜单的仓储接口里面:app
/// <summary> /// 菜单这个聚合根的仓储接口 /// </summary> public interface IMenuRepository:IRepository<TB_MENU> { IQueryable<TB_MENU> GetMenusByRole(TB_ROLE oRole); }
对应仓储实现:ide
[Export(typeof(IMenuRepository))] public class MenuRepository:EFBaseRepository<TB_MENU>,IMenuRepository { public IQueryable<TB_MENU> GetMenusByRole(TB_ROLE oRole) { var queryrole = UnitOfWork.context.Set<TB_ROLE>().AsQueryable(); var querymenu = UnitOfWork.context.Set<TB_MENU>().AsQueryable(); var querymenurole = UnitOfWork.context.Set<TB_MENUROLE>().AsQueryable(); var lstres = from menu in querymenu from menurole in querymenurole from role in queryrole where menu.MENU_ID == menurole.MENU_ID && menurole.ROLE_ID == role.ROLE_ID && role.ROLE_ID == oRole.ROLE_ID select menu; return lstres; } }
这里也是返回的IQueryable接口的集合,千万不要小看IQueryable接口,它是一种表达式树,能够延迟查询。也就是说,在咱们执行GetMenusByRole()以后,获得的是一个带有查询sql语句的表达式树结构,并无去数据库执行查询,只有在咱们ToList()的时候才会去查询数据库。咱们来写个Demo测试下。post
class Program { [Import] public IUserRepository userRepository { get; set; } [Import] public IMenuRepository menuRepository { get; set; } static void Main(string[] args) { //注册MEF var oProgram = new Program(); Regisgter.regisgter().ComposeParts(oProgram); var lstFindUsers = oProgram.userRepository.Find(x => x.USER_NAME !=null); var lstRes = lstFindUsers.ToList(); var lstMenu = oProgram.menuRepository.GetMenusByRole(new TB_ROLE() { ROLE_ID = "aaaa" }); var lstMenuRes = lstMenu.ToList(); } }
来看执行过程:测试
当程序执行var lstMenu = oProgram.menuRepository.GetMenusByRole(new TB_ROLE() { ROLE_ID = "aaaa" })这一步的时候基本是不耗时的,由于这一步仅仅是在构造表达式树,只有在.ToList()的时候才会有查询等待。更多详细能够看看此文 Repository 返回 IQueryable?仍是 IEnumerable?。this
在dax.net的系列文章中,提到了规约模式的概念,用于解决条件查询的问题。博主感受这个东西设计确实牛叉,但实用性不太强,通常中小型的项目也用不上。有兴趣能够看看规约(Specification)模式。