标签 标签 标签

  • 一句话的事儿:

前言:上篇介绍了下仓储的代码架构示例以及简单分析了仓储了使用优势。本章还是继续来完善下仓储的设计。上章说了,仓储的最主要作用的分离领域层和具体的技术架构,使得领域层更加专注领域逻辑。那么涉及到具体的实现的时候我们应该怎么做呢,本章就来说说仓储里面具体细节方便的知识。
DDD领域驱动设计初探系列文章:

2、查询和删除增加了传参lamada表达式的方法

仓储接口:

  1. public interface IRepository<TEntity> where TEntity : AggregateRoot
  2. {
  3. //...........
  4. #region 公共方法
  5. /// <summary>
  6. /// 根据lamada表达式查询集合
  7. /// </summary>
  8. /// <param name="selector">lamada表达式</param>
  9. /// <returns></returns>
  10. IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> express);
  11. /// <summary>
  12. /// 根据lamada表达式删除对象
  13. /// </summary>
  14. /// <param name="selector"> lamada表达式 </param>
  15. /// <returns> 操作影响的行数 </returns>
  16. int Delete(Expression<Func<TEntity, bool>> express);
  17. //..........
  18. }

仓储的实现

  1. //仓储的泛型实现类
  2. public class EFBaseRepository<TEntity> : IRepository<TEntity> where TEntity : AggregateRoot
  3. {
  4. //.............
  5. public virtual IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> express)
  6. {
  7. Func<TEntity, bool> lamada = express.Compile();
  8. return UnitOfWork.context.Set<TEntity>().Where(lamada).AsQueryable<TEntity>();
  9. }
  10. public virtual int Delete(Expression<Func<TEntity, bool>> express)
  11. {
  12. Func<TEntity, bool> lamada = express.Compile();
  13. var lstEntity = UnitOfWork.context.Set<TEntity>().Where(lamada);
  14. foreach (var entity in lstEntity)
  15. {
  16. UnitOfWork.RegisterDeleted(entity);
  17. }
  18. return UnitOfWork.Commit();
  19. }
  20. //.............
  21. }

增加这两个方法之后,对于单表的一般查询都可以直接通过lamada表示式的方法传入即可,并且返回值为IQueryable类型。

3、对于涉及到多张表需要连表的查询机制,我们还是通过神奇的Linq来解决。例如我们有一个通过角色取角色对应的菜单的接口需求。

在菜单的仓储接口里面:

  1. /// <summary>
  2. /// 菜单这个聚合根的仓储接口
  3. /// </summary>
  4. public interface IMenuRepository:IRepository<TB_MENU>
  5. {
  6. IQueryable<TB_MENU> GetMenusByRole(TB_ROLE oRole);
  7. }

对应仓储实现:

  1. [Export(typeof(IMenuRepository))]
  2. public class MenuRepository:EFBaseRepository<TB_MENU>,IMenuRepository
  3. {
  4. public IQueryable<TB_MENU> GetMenusByRole(TB_ROLE oRole)
  5. {
  6. var queryrole = UnitOfWork.context.Set<TB_ROLE>().AsQueryable();
  7. var querymenu = UnitOfWork.context.Set<TB_MENU>().AsQueryable();
  8. var querymenurole = UnitOfWork.context.Set<TB_MENUROLE>().AsQueryable();
  9. var lstres = from menu in querymenu
  10. from menurole in querymenurole
  11. from role in queryrole
  12. where menu.MENU_ID == menurole.MENU_ID &&
  13. menurole.ROLE_ID == role.ROLE_ID &&
  14. role.ROLE_ID == oRole.ROLE_ID
  15. select menu;
  16. return lstres;
  17. }
  18. }

这里也是返回的IQueryable接口的集合,千万不要小看IQueryable接口,它是一种表达式树,可以延迟查询。也就是说,在我们执行GetMenusByRole()之后,得到的是一个带有查询sql语句的表达式树结构,并没有去数据库执行查询,只有在我们ToList()的时候才会去查询数据库。我们来写个Demo测试下。

  1. class Program
  2. {
  3. [Import]
  4. public IUserRepository userRepository { get; set; }
  5. [Import]
  6. public IMenuRepository menuRepository { get; set; }
  7. static void Main(string[] args)
  8. {
  9. //注册MEF
  10. var oProgram = new Program();
  11. Regisgter.regisgter().ComposeParts(oProgram);
  12. var lstFindUsers = oProgram.userRepository.Find(x => x.USER_NAME !=null);
  13. var lstRes = lstFindUsers.ToList();
  14. var lstMenu = oProgram.menuRepository.GetMenusByRole(new TB_ROLE() { ROLE_ID = "aaaa" });
  15. var lstMenuRes = lstMenu.ToList();
  16. }
  17. }

来看执行过程:
DDD领域驱动设计初探(三):仓储Repository(下) - 图1
当程序执行var lstMenu = oProgram.menuRepository.GetMenusByRole(new TB_ROLE() { ROLE_ID = “aaaa” })这一步的时候基本是不耗时的,因为这一步仅仅是在构造表达式树,只有在.ToList()的时候才会有查询等待。更多详细可以看看此文 Repository 返回 IQueryable?还是 IEnumerable?
在dax.net的系列文章中,提到了规约模式的概念,用于解决条件查询的问题。博主感觉这个东西设计确实牛叉,但实用性不太强,一般中小型的项目也用不上。有兴趣可以看看规约(Specification)模式


  • 本文作者:GeekPower - Felix Sun
  • 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!