C#进阶系列——DDD领域驱动设计初探(三):仓储Repository(下)
前言:上篇介绍了下仓储的代码架构示例以及简单分析了仓储了使用优势。本章还是继续来完善下仓储的设计。上章说了,仓储的最主要作用的分离领域层和具体的技术架构,使得领域层更加专注领域逻辑。那么涉及到具体的实现的时候我们应该怎么做呢,本章就来说说仓储里面具体细节方便的知识。
DDD领域驱动设计初探系列文章:
- C#进阶系列——DDD领域驱动设计初探(一):聚合
- C#进阶系列——DDD领域驱动设计初探(二):仓储Repository(上)
- C#进阶系列——DDD领域驱动设计初探(三):仓储Repository(下)
- C#进阶系列——DDD领域驱动设计初探(四):WCF搭建
- C#进阶系列——DDD领域驱动设计初探(五):AutoMapper使用
- C#进阶系列——DDD领域驱动设计初探(六):领域服务
- C#进阶系列——DDD领域驱动设计初探(七):Web层的搭建
一、对仓储接口以及实现基类的完善
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 ;
}
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)模式。
C#进阶系列——DDD领域驱动设计初探(三):仓储Repository(下)的更多相关文章
- C#进阶系列——DDD领域驱动设计初探(一):聚合
前言:又有差不多半个月没写点什么了,感觉这样很对不起自己似的.今天看到一篇博文里面写道:越是忙人越有时间写博客.呵呵,似乎有点道理,博主为了证明自己也是忙人,这不就来学习下DDD这么一个听上去高大上的 ...
- C#进阶系列——DDD领域驱动设计初探(二):仓储Repository(上)
前言:上篇介绍了DDD设计Demo里面的聚合划分以及实体和聚合根的设计,这章继续来说说DDD里面最具争议的话题之一的仓储Repository,为什么Repository会有这么大的争议,博主认为主要原 ...
- C#进阶系列——DDD领域驱动设计初探(四):WCF搭建
前言:前面三篇分享了下DDD里面的两个主要特性:聚合和仓储.领域层的搭建基本完成,当然还涉及到领域事件和领域服务的部分,后面再项目搭建的过程中慢慢引入,博主的思路是先将整个架构走通,然后一步一步来添加 ...
- C#进阶系列——DDD领域驱动设计初探(五):AutoMapper使用
前言:前篇搭建了下WCF的代码,就提到了DTO的概念,对于为什么要有这么一个DTO的对象,上章可能对于这点不太详尽,在此不厌其烦再来提提它的作用: 从安全上面考虑,领域Model都带有领域业务,让Cl ...
- C#进阶系列——DDD领域驱动设计初探(六):领域服务
前言:之前一直在搭建项目架构的代码,有点偏离我们的主题(DDD)了,这篇我们继续来聊聊DDD里面另一个比较重要的知识点:领域服务.关于领域服务的使用,书中也介绍得比较晦涩,在此就根据博主自己的理解谈谈 ...
- C#进阶系列——DDD领域驱动设计初探(七):Web层的搭建
前言:好久没更新博客了,每天被该死的业务缠身,今天正好一个模块完成了,继续来完善我们的代码.之前的六篇完成了领域层.应用层.以及基础结构层的部分代码,这篇打算搭建下UI层的代码. DDD领域驱动设计初 ...
- DDD领域驱动设计初探(七):Web层的搭建
前言:好久没更新博客了,每天被该死的业务缠身,今天正好一个模块完成了,继续来完善我们的代码.之前的六篇完成了领域层.应用层.以及基础结构层的部分代码,这篇打算搭建下UI层的代码. DDD领域驱动设计初 ...
- DDD领域驱动设计初探(六):领域服务
前言:之前一直在搭建项目架构的代码,有点偏离我们的主题(DDD)了,这篇我们继续来聊聊DDD里面另一个比较重要的知识点:领域服务.关于领域服务的使用,书中也介绍得比较晦涩,在此就根据博主自己的理解谈谈 ...
- DDD领域驱动设计初探(五):AutoMapper使用
前言:前篇搭建了下WCF的代码,就提到了DTO的概念,对于为什么要有这么一个DTO的对象,上章可能对于这点不太详尽,在此不厌其烦再来提提它的作用: 从安全上面考虑,领域Model都带有领域业务,让Cl ...
随机推荐
- vue+ vue-router + webpack 踩坑之旅
说是踩坑之旅 其实是最近在思考一些问题 然后想实现方案的时候,就慢慢的查到这些方案 老司机可以忽略下面的内容了 1)起因 考虑到数据分离的问题 因为server是express搭的 自然少 ...
- JavaScript 变量
一,JavaScript 变量(存储信息的容器) 与代数一样,JavaScript 变量可用于存放值(比如 x=2)和表达式(比如 z=x+y). 变量可以使用短名称(比如 x 和 y),也可以使用描 ...
- C# Stream 和 byte[] 之间的转换
一. 二进制转换成图片 MemoryStream ms = new MemoryStream(bytes); ms.Position = ; Image img = Image.FromStream( ...
- 【代码笔记】iOS-向服务器传JSON数据的两种方式
一,代码. - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. ...
- iOS 杂笔-25(不要用copy修饰NSMutableString)
iOS 杂笔-25(不要用copy修饰NSMutableString) 首先对题目进行简单的解释,我所说的不要用copy修饰NSMutableString不是说完全不可以用.但是要清楚一点,既然使用N ...
- android 性能优化
本章介绍android高级开发中,对于性能方面的处理.主要包括电量,视图,内存三个性能方面的知识点. 1.视图性能 (1)Overdraw简介 Overdraw就是过度绘制,是指在一帧的时间内(16. ...
- IOS开发之Bug--遇到一个类型不确定的bug
下面的问题不大,是我在开发中遇到的问题: 然后我就google搜一下这个报错 . 下面就解决了:
- C#实现在图片上斜着写字
最近公司要搞微信活动页面,要实现图片上可以写自己名字的功能,于是就查了一下怎么实现,下面贴一下代码备忘,希望大家也能用到: 我是在控制台应用程序里进行试验的. using (Image bitmap ...
- 深入理解Linux修改hostname
当我觉得对Linux系统下修改hostname已经非常熟悉的时候,今天碰到了几个个问题,这几个问题给我好好上了一课,很多知识点,当你觉得你已经掌握的时候,其实你了解的还只是皮毛.技术活,切勿浅尝则止! ...
- Java 堆
特性: 虚拟机启动时创建的线程共享的内存区域,所有实例对象和数组对象分配内存的区域 GC垃圾手机管理器管理的主要区域,GC堆 容量可以固定,也可以动态扩展,自动收缩 -Xmx最大堆大小 -Xms最小. ...