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 ...
随机推荐
- express源码剖析1
在通读源码之前,先把一些比较难理解的代码吃透: 1.EventEmitter.prototype mixin(app, EventEmitter.prototype, false); app为一个函数 ...
- mysql ,服务器耗时测试
测试一 字段:ID,test,number 电脑配置:8g内存 同时写入超过5w条,就会卡死 错误提示 Fatal error: Allowed memory size of bytes exhaus ...
- Windows下LATEX排版论文攻略—CTeX、JabRef使用介绍
Windows下LATEX排版论文攻略—CTeX.JabRef使用介绍 一.工具介绍 TeX是一个很好排版工具,在学术界十分流行,特别是数学.物理学和计算机科学界. CTeX是TeX中的一个版本,指的 ...
- 显示oracle表的分区信息
显示分区表信息 显示数据库所有分区表的信息:DBA_PART_TABLES 显示当前用户可访问的所有分区表信息:ALL_PART_TABLES 显示当前用户所有分区表的信息:USER_PART_TAB ...
- Linux htop工具使用详解
一.Htop的使用简介 大家可能对top监控软件比较熟悉,今天我为大家介绍另外一个监控软件Htop,姑且称之为top的增强版,相比top其有着很多自身的优势.如下: 两者相比起来,top比较繁琐 默认 ...
- 分分钟教你从根本上认识Struts2框架
在了解Struts2之前我们先来聊聊Struts1,我们都知道在很长的一段时间内,所有的MVC框架中,Struts1他是处于一个超级大咖的地位,无论是从市场角度和使用的用户的数量这个角度而言,Stru ...
- css兼容性大坑
一. \:选择IE6+//区分 IE 8(不实用) .title{ color:yellow\0; color: red\9\0;} \9在 IE 6及其以上都可以识别(但是 IE11不识别 ,IE ...
- webstorm ES6 转 ES5
一句话总结:用WebStorm自带的File Watcher功能+Babel实现自动转换ECMAScript 6代码为ES5代码 1. 新建一个Empty Project,然后在src目录下新建了一个 ...
- 第三篇 基于.net搭建热插拔式web框架(重造Controller)
由于.net MVC 的controller 依赖于HttpContext,而我们在上一篇中的沙箱模式已经把一次http请求转换为反射调用,并且http上下文不支持跨域,所以我们要重造一个contro ...
- qlikview 扩展插件制作教程-EchartsGeoMap
效果图 显示效果和echarts官方demo一样,运行速度尚可. 第一次写博客,排版很渣以后慢慢改进. 基础知识 以EchartsGeoMap为例,讲一下怎么制作一个基础的QlikView Ext ...