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

DDD领域驱动设计初探系列文章:

一、对仓储接口以及实现基类的完善

1、仓储实现基类的所有方法加上virtual关键字,方便具体的仓储在特定需求的时候override基类的方法。

  //仓储的泛型实现类
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();
}
}

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

仓储接口:

   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); //..........
  }

仓储的实现

   //仓储的泛型实现类
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类型。

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

在菜单的仓储接口里面:

   /// <summary>
/// 菜单这个聚合根的仓储接口
/// </summary>
public interface IMenuRepository:IRepository<TB_MENU>
{
IQueryable<TB_MENU> GetMenusByRole(TB_ROLE oRole);
}

对应仓储实现:

  [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测试下。

   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?

在dax.net的系列文章中,提到了规约模式的概念,用于解决条件查询的问题。博主感觉这个东西设计确实牛叉,但实用性不太强,一般中小型的项目也用不上。有兴趣可以看看规约(Specification)模式

DDD领域驱动设计初探(三):仓储Repository(下)的更多相关文章

  1. C#进阶系列——DDD领域驱动设计初探(三):仓储Repository(下)

    前言:上篇介绍了下仓储的代码架构示例以及简单分析了仓储了使用优势.本章还是继续来完善下仓储的设计.上章说了,仓储的最主要作用的分离领域层和具体的技术架构,使得领域层更加专注领域逻辑.那么涉及到具体的实 ...

  2. C#进阶系列——DDD领域驱动设计初探(二):仓储Repository(上)

    前言:上篇介绍了DDD设计Demo里面的聚合划分以及实体和聚合根的设计,这章继续来说说DDD里面最具争议的话题之一的仓储Repository,为什么Repository会有这么大的争议,博主认为主要原 ...

  3. DDD领域驱动设计初探(二):仓储Repository(上)

    前言:上篇介绍了DDD设计Demo里面的聚合划分以及实体和聚合根的设计,这章继续来说说DDD里面最具争议的话题之一的仓储Repository,为什么Repository会有这么大的争议,博主认为主要原 ...

  4. C#进阶系列——DDD领域驱动设计初探(一):聚合

    前言:又有差不多半个月没写点什么了,感觉这样很对不起自己似的.今天看到一篇博文里面写道:越是忙人越有时间写博客.呵呵,似乎有点道理,博主为了证明自己也是忙人,这不就来学习下DDD这么一个听上去高大上的 ...

  5. C#进阶系列——DDD领域驱动设计初探(四):WCF搭建

    前言:前面三篇分享了下DDD里面的两个主要特性:聚合和仓储.领域层的搭建基本完成,当然还涉及到领域事件和领域服务的部分,后面再项目搭建的过程中慢慢引入,博主的思路是先将整个架构走通,然后一步一步来添加 ...

  6. C#进阶系列——DDD领域驱动设计初探(五):AutoMapper使用

    前言:前篇搭建了下WCF的代码,就提到了DTO的概念,对于为什么要有这么一个DTO的对象,上章可能对于这点不太详尽,在此不厌其烦再来提提它的作用: 从安全上面考虑,领域Model都带有领域业务,让Cl ...

  7. C#进阶系列——DDD领域驱动设计初探(六):领域服务

    前言:之前一直在搭建项目架构的代码,有点偏离我们的主题(DDD)了,这篇我们继续来聊聊DDD里面另一个比较重要的知识点:领域服务.关于领域服务的使用,书中也介绍得比较晦涩,在此就根据博主自己的理解谈谈 ...

  8. C#进阶系列——DDD领域驱动设计初探(七):Web层的搭建

    前言:好久没更新博客了,每天被该死的业务缠身,今天正好一个模块完成了,继续来完善我们的代码.之前的六篇完成了领域层.应用层.以及基础结构层的部分代码,这篇打算搭建下UI层的代码. DDD领域驱动设计初 ...

  9. DDD领域驱动设计初探

    DDD领域驱动设计初探1 前言:又有差不多半个月没写点什么了,感觉这样很对不起自己似的.今天看到一篇博文里面写道:越是忙人越有时间写博客.呵呵,似乎有点道理,博主为了证明自己也是忙人,这不就来学习下D ...

随机推荐

  1. 我写过的bug...

    添加对,更新和查询出错 因为只写了bean里只写了se't方法,没有写get 多条件联合查询,后一个条件没用 写xml里面复制上一行,忘记把变量名改了(propertyValue没改成register ...

  2. GO开发:etcd用法

    etcd是什么? A highly-available key value store for shared configuration and service discovery.是一个键值存储仓库 ...

  3. Mysql的caching_sha2_password的坑

    概述 今天我用homebrew安装Mysql8.0,安装完成之后,用Workbench和Sequel Pro连接数据库都失败了,并且都报caching_sha2_password相关的错误,经过查资料 ...

  4. kafka 消费者拉取消息

    本文只跟踪消费者拉取消息的流程.对于 java 客户端, kafka 的生产者和消费者复用同一个网络 io 类 NetworkClient. 入口在 KafkaConsumer#pollOnce 中, ...

  5. Octavia 的实现与分析(OpenStack Rocky)

    目录 文章目录 目录 Octavia 基本对象概念 基本使用流程 软件架构 服务进程清单 代码结构 loadbalancer 创建流程分析 network_tasks.AllocateVIP netw ...

  6. OpenStack Nova 高性能虚拟机之 NUMA 架构亲和

    目录 文章目录 目录 写在前面 计算平台体系结构 SMP 对称多处理结构 NUMA 非统一内存访问结构 MPP 大规模并行处理结构 Linux 上的 NUMA 基本对象概念 NUMA 调度策略 获取宿 ...

  7. dotnet core排序异常,本地测试和linux上结果不一致

    根据汉字排序,本地测试结构正常,发到docker之后,发现汉字升序降序和本地相反,检查代码后,没找到任何可能出现问题的点. 然后去翻文档:字符串比较操作 看到了这一句,会区分区域性 然后猜测应该是do ...

  8. 操作系统(1)——X86-32硬件介绍、实验环境相关配置、uCore部分技巧介绍

    实验环境 本文假设已经创建虚拟机并配置好Ubuntu 16.04(网上太多教程了,所以这里就不赘述了). X86-32硬件介绍 x86指的是80386这种机器(一种32位CPU,在早期得到了广泛的应用 ...

  9. 【Qt开发】【Linux开发】Qt程序在嵌入式设备(arm) 上运行,鼠标擦除界面的解决方案

    笔者最近想在arm开发板上,开发一个应用程序,经过网上查询发现qt作为跨平台开发软件很不错,于是便选择了qt开发,笔者的qt版本是4.8.6的.由于arm的主频太低,在arm上进行开发编译,效率会大大 ...

  10. (一)VS2015下配置OpenGL

    刚开始用OpenGL,一开始不太明白配置库的原理,在VS2015下耗费了大量时间.这里将配置过程做个笔记,以供日后查看.配置过程中,需要下载cmake构建工具以及glew和glfw库. 下载地址为: ...