企业建站系统开源,嘉兴seo收费,软件优化,推荐常州模板网站建设1.引言
实体对应的英语单词为Entity。提到实体#xff0c;你可能立马就想到了代码中定义的实体类。在使用一些ORM框架时#xff0c;比如Entity Framework#xff0c;实体作为直接反映数据库表结构的对象#xff0c;就更尤为重要。特别是当我们使用EF Code First时#xf…1.引言
实体对应的英语单词为Entity。提到实体你可能立马就想到了代码中定义的实体类。在使用一些ORM框架时比如Entity Framework实体作为直接反映数据库表结构的对象就更尤为重要。特别是当我们使用EF Code First时我们首先要做的就是实体类的设计。在DDD中实体作为领域建模的工具之一也是十分重要的概念。
但DDD中的实体和我们以往开发中定义的实体是同一个概念吗不完全是。在以往未实施DDD的项目中我们习惯于将关注点放在数据上而非领域上。这也就说明了为什么我们在软件开发过程中会首先做数据库的设计进而根据数据库表结构设计相应的实体对象这样的实体对象是数据模型转换的结果。在DDD中实体作为一个领域概念在设计实体时我们将从领域出发。
2.DDD中的实体
DDD中要求实体是唯一的且可持续变化的。意思是说在实体的生命周期内无论其如何变化其仍旧是同一个实体。唯一性由唯一的身份标识来决定的。可变性也正反映了实体本身的状态和行为。
3. 唯一标识
举个例子在有双胞胎的家庭里家人都可以快速分辨开来。这得益于家人对双胞胎性格和外貌的区分。然而邻居却不能只能通过名字来区分。上小学后学校里尽然有重名的这时候就要取外号区分了。上大学后要坐火车去学校买票时就要用身份证号来区分了。
针对这个例子如果我们要抽象出一个User实体要如何定义其唯一标识呢其中性格、外貌、昵称、身份证号都可以作为User实体的属性在某些场景下某个属性就可以对对象进行区分。但为了确保标识的稳定性我们只能将身份证号设为唯一身份标识。
3.1.唯一标识的类型
唯一标识的类型在不同的场景又有不同的要求。主要可以分为有意义和无意义两种。在一个简单的应用程序里一个int类型的自增Id就可以作为唯一标识。优点就是占用空间小查询速度快。而在一些业务当中要求唯一标识有意义通过唯一标识就能识别出一些基本信息比如支付宝的交易号其中就包含了日期和用户ID。这种就属于字符串类型的标识这就对唯一标识的生成提出了挑战。在一些复杂的业务流程中对唯一标识没有要求我们可以使用GUID类型来生成唯一标识很显然GUID占用空间就毕竟大且不利于查询。
3.2.唯一标识的生成时机
有某些场景下唯一标识的生成时机也各不相同主要分为即时生成和延迟生成。即时生成即在持久化实体之前先申请唯一标识再更新到数据库。延迟生成即在持久化实体之后。
3.3.委派标识和领域标识
基于领域实体概念分析确定的唯一身份标识我们可以称为领域实体标识。而在有些ORM工具比如Hibernate、EF它们有自己的方式来处理对象的身份标识。它们倾向于使用数据库提供的机制比如使用一个数值序列来生成识。在ORM中委派标识表现为int或long类型的实体属性来作为数据库的主键。很显然委派标识是为了迎合ORM而创建的且委派标识和领域实体标识无任何关系。
那既然ORM需要委派标识我们就可以创建一个实体基类来统一指定委派标识。而这个实体基类又被称为层超类型。
3.3.1.实现层超类型
首先定义层超类型接口
public interface IEntity
{
}public interface IEntityTPrimaryKey : IEntity
{TPrimaryKey Id { get; set; }
}
通过定义泛型接口以支持自定义主键类型。
实现层超类型 public class Entity : Entityint, IEntity { } public class EntityTPrimaryKey : IEntityTPrimaryKey { public virtual TPrimaryKey Id { get; set; } public override bool Equals(object obj) { if (obj null || !(obj is EntityTPrimaryKey)) { return false; } //Same instances must be considered as equal if (ReferenceEquals(this, obj)) { return true; } //Must have a IS-A relation of types or must be same type var typeOfThis GetType(); var typeOfOther other.GetType(); if (!typeOfThis.GetTypeInfo().IsAssignableFrom(typeOfOther) !typeOfOther.GetTypeInfo().IsAssignableFrom(typeOfThis)) { return false; } return Id.Equals(other.Id); } public override int GetHashCode() { return Id.GetHashCode(); } public static bool operator (EntityTPrimaryKey left, EntityTPrimaryKey right) { if (Equals(left, null)) { return Equals(right, null); } return left.Equals(right); } public static bool operator !(EntityTPrimaryKey left, EntityTPrimaryKey right) { return !(left right); } }
可以看到默认的委托标识为int类型。我们重写了EqualsGetHashCode方法以及和!两个操作符。
通过这样一种方式我们进行约定所有的实体必须继承自Entity即可实现委托标识的统一定义。
4.可变性
解决了实体的唯一身份标识问题后我们就可以保证其生命周期中的连续性不管其如何变化。
那可变性说的是什么呢可变性是实体的状态和行为。而实体的状态和行为就要对具体的业务模型加以分析提炼出通用语言再基于通用语言来抽象成实体对应的属性或方法。 我们拿订单环节来举例说明当顾客从购物车点击结算时创建订单初始状态为未支付状态支付成功后切换到正常状态此时可对订单做发货处理并置为已发货状态。当顾客签收后将订单关闭。 从以上的通用语言的描述中在通用语言的术语中名词用于给概念命名形容词用于描述这些概念而动词则表示可以完成的操作。我们可以提取订单的相关状态和行为
订单状态未支付、正常、已发货、关闭。针对状态我们需定义一个状态属性即可。订单的行为支付、发货和关闭。针对行为我们可以在实体中定义方法或创建单独的领域服务来处理。
实体既然存在状态和行为就必然会与事件有所牵连。比如订单支付成功后需要知会商家发货。这时我们就要追踪订单状态的变化而追踪变化最实用的方法就是领域事件。关于领域事件我们后续再讲。
5.实体的验证
验证的目的是为了检查模型的正确性和有效性。检查的对象可以为某个属性也可以是整个对象或是多个对象的组合。针对验证的方式不一而足根据需要可自行发挥。
6.总结
实体作为领域建模的工具之一唯一的身份标识是实体最基本的特征其次是可变性。唯一身份标识和可变性也是用来区分实体和值对象的主要特征。
为了正确建立实体模型我们需要将关注点从数据转向领域从业务模型中提炼通用语言再基于通用语言分析其状态和行为。
所以我们可以认为实体 唯一身份标识 可变性【状态属性 行为方法或领域事件或领域服务】
相关文章
DDD理论学习系列1-- 通用语言DDD领域驱动之干货 一DDD理论学习系列2-- 领域DDD理论学习系列3-- 限界上下文DDD理论学习系列4-- 领域模型事件总线知多少2DDD理论学习系列5-- 统一建模语言从事件和DDD入手来构建微服务DDD领域驱动之干货 一WeText项目一个基于.NET实现的DDD、CQRS与微服务架构的演示案例【DDD/CQRS/微服务架构案例】在Ubuntu 14.04.4 LTS中运行WeText项目的服务端
原文地址http://www.cnblogs.com/sheng-jie/p/6991095.html .NET社区新闻深度好文微信中搜索dotNET跨平台或扫描二维码关注