DDD分层架构之领域实体(基础篇)
2014-11-17 20:46
417 查看
DDD分层架构之领域实体(基础篇)
上一篇,我介绍了自己在DDD分层架构方面的一些感想,本文开始介绍领域层的实体,代码主要参考自《领域驱动设计C#2008实现》,另外参考了网上找到的一些示例代码。什么是实体
由标识来区分的对象称为实体。实体的定义隐藏了几个信息:
两个实体对象,只要它们的标识属性值相等,哪怕标识属性以外的所有属性值都不相等,这两个对象也认为是同一个实体,这意味着两个对象是同一实体在其生命周期内的不同阶段。
为了能正确区分实体,标识必须唯一。
实体的标识属性值是不可变的,标识属性以外的属性值是可变的。如果标识值不大稳定,偶尔会变化,那么就无法将该实体在生命周期内的所有变化关联在一起,这可能导致严重的问题。
实体标识
从实体的定义可以发现,标识是实体的关键特征。关于标识,有几个值得思考的问题。将什么选作标识
比如中国人都有身份证,身份证号码是唯一的,那么可能会有人使用身份证号作为实体标识。这看起来好像没什么问题,但身份证每隔N年就会换代,身份证号可能发生变化。这违反了标识不可变性和稳定性要求,所以不适合作为实体标识。对于手工录入流水号作为实体标识的情况,要用户自己保证唯一性已经很困难,如果提供了修改标识的功能,将导致标识不稳定,如果不提供,用户录入错误就只能删除后重新输入,这就太不人道了。
通过程序自动生成一个有意义的流水号作为实体标识,并且不提供修改,这可能是可行的,对于唯一性要求,程序和数据库可以保证,另外不允许修改,就可以保证稳定性。对于像订单号一类的场景可能有效。
可以看到,使用有意义的值作为标识有一定风险,并且难度比较大,为了简单和方便,生成一个无意义的唯一值作为标识更可行。
为标识选择什么类型
对于使用Sql Server的同学,一般会倾向于使用int类型,映射到数据库中的自增长int。它的优势是简单,唯一性由数据库保障,占用空间小,查询速度快。我之前也采用了很长时间,大部分时候很好用,不过偶尔会很头痛。由于实体标识需要等到插入数据库之后才创建出来,所以你在保存之前不可能知道标识值是多少,如果在保存之前需要拿到Id,唯一的方法是先插入数据库,得到Id以后,再执行另外的操作,换句话说,需要把本来是同一个事务中的操作分成多个事务执行。
使用自增长int类型的第二个毛病是,如果需要合并同一个实体对应的多个数据表记录,悲剧就会发生。比如你现在把一个实体对应的记录水平分区到多个数据库的表中,由于Id是自增长的,每个表都会从1开始自增,你要合并到一个表中,Id就会发生冲突。所以对于比较大点的项目,使用自增长int类型是有一些风险的。
对于比较小,且不是太复杂的项目,使用自增长int类型是个不错的选择,但如果你经常碰到上面提到的问题,说明你需要重新选择标识类型了。
要解决以上问题,最简单的方法是选择Guid作为标识类型。
它的主要优势是生成Guid非常容易,不论是Js,C#还是在数据库中,都能轻易的生成出来。另外,Guid的唯一性很强,基本不可能生成出两个相同的Guid。
Guid类型的主要缺点是占用空间太大。另外实体标识一般映射到数据库的主键,而Sql Server会默认把主键设成聚集索引,由于Guid的不连续性,这可能导致大量的页拆分,造成大量碎片从而拖慢查询。一个解决办法是使用Sql Server来生成Guid,它可以生成连续的Guid值,但这又回到了老路,只有插入数据库你才知道具体的Id值,所以行不通。另一个解决办法是把聚集索引移到其它列上,比如创建时间。如果你打算把聚集索引继续放到Guid标识列上,可以观察到碎片一般都在90%以上,写一个Sql脚本,定时在半夜整理一下碎片,也算一个勉强的办法。
如果生成一个有意义的流水号来作为标识,这时候标识类型就是一个字符串。
有些时候可能还要使用更复杂的组合标识,这一般需要创建一个值对象作为标识类型。
我目前一般都使用Guid作为标识类型,偶尔使用字符串类型。
对于需要更详细的了解实体标识,请参考《企业应用架构模式》标识域一节。
实体层超类型的实现
既然每个实体都有一个标识,那么为所有实体创建一个基类就显得很有用了,这个基类就是层超类型,它为所有领域实体提供基础服务。为了降低依赖性,现在需要在本系列应用程序框架的VS解决方案中增加一个类库Util.Domains和单元测试项目Util.Domains.Tests,并使用解决方案文件夹进行分类,如下图所示。
单元测试代码
完整EntityBase代码如下。
EntityBase
为了完成实体基类的验证,我需要先提供两个公共操作类,即验证和自定义异常类,待把这两个类完成后,我们再继续介绍实体基类在验证方面的支持。
.Net应用程序框架交流QQ群: 386092459,欢迎有兴趣的朋友加入讨论。如果发现代码中有BUG,请及时告知,我将迅速修复。
谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/xiadao521/
下载地址:http://files.cnblogs.com/xiadao521/Util.2014.11.17.1.rar
相关文章推荐
- 应用程序框架实战十四:DDD分层架构之领域实体(基础篇)
- 应用程序框架(一):DDD分层架构:领域实体(基础篇)
- DDD分层架构之领域实体(验证篇)
- 应用程序框架实战十五:DDD分层架构之领域实体(验证篇)
- 【转载】实体框架之领域驱动实践(二):分层架构
- 【转载】实体框架之领域驱动实践:分层架构
- 应用程序框架实战二十二 : DDD分层架构之仓储(层超类型基础篇)
- DDD, 企业架构, 分层架构, 领域模型, PetShop 4.0
- MVC无限级分类01,分层架构,引入缓存,完成领域模型与视图模型的映射
- 【转载】DDD分层架构的三种模式
- 干货 | DDD实战:基于洋葱模型的分层代码架构设计
- 应用程序框架实战十六:DDD分层架构之值对象(介绍篇)
- ddd的战术: 分层设计和应用架构
- 选用面向领域的多层分布式架构(DDD风格架构)的理由
- Evans DDD(领域驱动开发) 与架构分层
- DDD领域驱动设计之聚合、实体、值对象
- Rafy 领域实体框架演示(3) - 快速使用 C/S 架构部署
- DDD分层架构之我见
- DDD分层架构之值对象(介绍篇)
- DDD领域驱动设计与SOA面向服务架构