EF不能很好的支持DDD?估计是我们搞错了!
(此文章同时发表在本人微信公众号“dotNET每日精华文章”,欢迎右边二维码来关注。)
题记:最近在ABP项目中尝试纯粹的DDD,然后遇到EF实现的Repository似乎不能很好支持DDD,但……可能是我们搞错了。
ABP即ASP.NET Boilerplate,一个融合了很多最佳实践(比如领域驱动设计,Domain Driven Design,DDD)的应用程序开发框架。当然,ABP并没有强制要求你严格使用DDD中的概念来开发。换句话说,也可以很好的支持DDD的概念,比如仓储(Repository)的概念(ABP分别提供了Entity Framework和NHibernate的实现)。
ABP在刚刚更新的0.13.0版本中引入了名为AggregateRoot的基类,可以让你方便的引入DDD中的聚合和聚合根的概念了。
不过我在基于聚合来实现功能的时候,遇到了一个问题:在EF的Repository实现下,聚合中的实体无法通过聚合根来正确删除。举例来说,假设聚合中包含Order和OrderLine两个实体,Order是聚合根,那么如果通过
Order.OrderLines.Remove(orderLine)
这样的代码来删除OrderLine数据的话,就会报错。类似的问题很多人其实也遇到过,比如这篇文章就详细解释了这种情况:http://blog.raffaeu.com/archive/2014/10/04/entity-framework-6-and-collections-with-ddd.aspx。当然在stackoverflow上也有很多这样的提问。并且这个问题在2010年就被人在UserVoice提出来了,而微软一直都没有进行改变。
一开始,我也认为这是EF存在的缺陷。但是当我再次回顾聚合和聚合根中的相关特点的时候(以下文字引用于汤雪华的博文):
每个聚合有一个根和一个边界,边界定义了一个聚合内部有哪些实体或值对象,根是聚合内的某个实体;
聚合内部的对象之间可以相互引用,但是聚合外部如果要访问聚合内部的对象时,必须通过聚合根开始导航,绝对不能绕过聚合根直接访问聚合内的对象,也就是说聚合根是外部可以保持 对它的引用的唯一元素;
聚合内除根以外的其他实体的唯一标识都是本地标识,也就是只要在聚合内部保持唯一即可,因为它们总是从属于这个聚合的;
聚合根负责与外部其他对象打交道并维护自己内部的业务规则;
基于聚合的以上概念,我们可以推论出从数据库查询时的单元也是以聚合为一个单元,也就是说我们不能直接查询聚合内部的某个非根的对象;
聚合内部的对象可以保持对其他聚合根的引用;
删除一个聚合根时必须同时删除该聚合内的所有相关对象,因为他们都同属于一个聚合,是一个完整的概念;
同时也找出了一个被我们常常忽视的EF特点:标识和非标识关系的区别。所谓标识关系就是:主实体(即Order)的主键除了作为依赖实体(即OrderLine)的外键也要成为依赖实体的主键的一部分(即需要混合主键)。非标识关系就是:主实体的主键只作为依赖实体的外键。两种关系的最大不同就在于:标识关系下,依赖实体不能独立于主实体存在,删除主实体也会删除依赖实体(效果类似于级联删除),删除关系就会删除依赖实体。对于这一特点的详细说明可见此MSDN文档的"Considerations for Identifying and Non-identifying Relationships”。
结合DDD聚合的特点“聚合内除根以外的其他实体的唯一标识都是本地标识,也就是只要在聚合内部保持唯一即可”,以及上面提到的EF标识关系的特点“删除关系就会删除依赖实体”。我们可能错怪EF了,正确做法是:应该把聚合中的非根实体设置为标识关系。这样的建模方式即体现了OrderLine的ID是本地标识的特性(要全局唯一必须混合Order的ID),又满足了通过聚合根来删除明细实体的目的。
其实这是一个很细的设计和实现问题,很多人有遇到,当然在stackoverflow也有人给出了解决方案。我这里只是给出了一点自己的思考,意欲解释一下这个问题出现的根源和解决方案背后的理论基础。
EF不能很好的支持DDD?估计是我们搞错了!的更多相关文章
- DDD实战进阶第一波(四):开发一般业务的大健康行业直销系统(搭建支持DDD的轻量级框架三)
上一篇文章我们讲了经典DDD架构对比传统三层架构的优势,以及经典DDD架构每一层的职责后,本篇文章将介绍基础结构层中支持DDD的轻量级框架的主要代码. 这里需要说明的是,DDD轻量级框架能够体现DDD ...
- DDD实战进阶第一波(二):开发一般业务的大健康行业直销系统(搭建支持DDD的轻量级框架一)
要实现软件设计.软件开发在一个统一的思想.统一的节奏下进行,就应该有一个轻量级的框架对开发过程与代码编写做一定的约束. 虽然DDD是一个软件开发的方法,而不是具体的技术或框架,但拥有一个轻量级的框架仍 ...
- DDD实战进阶第一波(三):开发一般业务的大健康行业直销系统(搭建支持DDD的轻量级框架二)
了解了DDD的好处与基本的核心组件后,我们先不急着进入支持DDD思想的轻量级框架开发,也不急于直销系统需求分析和具体代码实现,我们还少一块, 那就是经典DDD的架构,只有了解了经典DDD的架构,你才能 ...
- python列表很聪明,支持负数索引
python列表很聪明,支持负数索引
- 一个很不错的支持Ext JS 4的上传按钮
以前经常使用的swfUpload,自从2010年开始到现在,很久没更新了.而这几年,flash版本已经换了好多个,所以决定抛弃swfupload,使用新找到的上传按钮. 新的上传按钮由harrydel ...
- ef查询mysql数据库数据支持DbFunctions函数
1.缘由 快下班的时候,一同事说在写linq查询语句时where条件中写两时间相减大于某具体天数报错:后来仔细一问,经抽象简化,可以总结为下面的公式: a.当前时间 减去 某表时间字段 大于 某具体天 ...
- 有了 Docker,用 JavaScript 框架开发的 Web 站点也能很好地支持网络爬虫的内容抓取
点这里 阅读目录 用 AngularJS(以及其它 JavaScript 框架)开发的 Web 站点不支持爬虫的抓取 解决方案 为什么公开我们的解决方案 实现 AngularJS 服务 结论 Pr ...
- 实体框架 (EF) 入门 => 三、CodeFirst 支持的完整特性列表
KeyAttribute 设置主键.如果为int类型,将自动设置为自增长列. 系统默认以Id或类名+Id作为主键.StringLengthAttribute 可设置最大最小长度以及验证提示信息等.最大 ...
- EF Core 2.0 已经支持自动生成父子关系表的实体
现在我们在SQL Server数据库中有Person表如下: CREATE TABLE [dbo].[Person]( ,) NOT NULL, ) NULL, ) NULL, ) NULL, [Cr ...
随机推荐
- jQuery校验
jQuery校验 官网地址:http://bassistance.de/jquery-plugins/jquery-plugin-validation 一导入js库 <script src=&q ...
- Java数据结构——树的三种存储结构
(转自http://blog.csdn.net/x1247600186/article/details/24670775) 说到存储结构,我们就会想到常用的两种存储方式:顺序存储和链式存储两种. 先来 ...
- CSS清浮动处理(Clear与BFC)
在CSS布局中float属性经常会被用到,但使用float属性后会使其在普通流中脱离父容器,让人很苦恼 1 浮动带来布局的便利,却也带来了新问题 <!doctype html> <h ...
- jquery 自定义click事件执行多次
用jquery绑定一个按钮click事件后,第一次点击后一切正常,第二次点击竟然执行两次,以后越来越多, 后来查看文档发现 jquery click 不是替换原有的function 而是接着添加,所以 ...
- Yii2 手动安装yii2-imagine插件
由于网络的原因使用composer安装Yii框架,实在太过痛苦,所以这里干脆就手动安装yii-imagine的扩展. 首先下载yii2-image和Imagine扩展库,点击链接就可以从百度云下载上传 ...
- 【Python文件处理】递归批处理文件夹子目录内所有txt数据
因为有个需求,需要处理文件夹内所有txt文件,将txt里面的数据筛选,重新存储. 虽然手工可以做,但想到了python一直主张的是自动化测试,就想试着写一个自动化处理数据的程序. 一.分析数据格式 需 ...
- matlab -xlsread 打开xls文件出错:服务器出现意外情况
错误:xlsread:服务器出现意外情况 原因:非matlab问题,Excel的com加载项启用 解决方法:office - Excel选项-加载项:管理-com加载项-转到-取消可用加载项的勾选.
- lombok 简化java代码注解
lombok 简化java代码注解 安装lombok插件 以intellij ide为例 File-->Setting-->Plugins-->搜索"lombok plug ...
- [MySQL] MySQL存储过程常用的函数
一.字符串类 CHARSET(str) //返回字串字符集 CONCAT (string2 [,... ]) //连接字串 INSTR (string ,substring ) //返回substr ...
- Linux下安装jetty服务器
jetty和我们通常使用的tomcat一样,是一个开源的servlet容器,特点是轻量易部署,一方面jetty可以作为web容器使用,另一方面也是最一般的方式是jetty以一组jar包的形式发布,所以 ...