Domain driven design DDD实体应该通过引用还是通过ID进行比较?

Domain driven design DDD实体应该通过引用还是通过ID进行比较?,domain-driven-design,equality,Domain Driven Design,Equality,当我开始使用DDD时,我在实体中创建了比较实体ID的Equals()方法。因此,具有相同ID的两个实体对象将被视为相等 在某种程度上,我思考了这一点,发现处于不同状态的两个实体不应该被认为是平等的,即使它们描述了相同的事物(即具有相同的ID)。现在我对实体使用引用等式 然后我被马克·希曼绊倒了,他在那里写作 如果实体的ID彼此相等,则它们是相等的 当然,现在我想知道哪种方法更好 编辑:请注意,问题不是同时拥有同一实体的两个实例是否是一个好主意。我知道在大多数情况下可能不是这样。我认为在不同的状态

当我开始使用DDD时,我在实体中创建了比较实体ID的
Equals()
方法。因此,具有相同ID的两个实体对象将被视为相等

在某种程度上,我思考了这一点,发现处于不同状态的两个实体不应该被认为是平等的,即使它们描述了相同的事物(即具有相同的ID)。现在我对实体使用引用等式

然后我被马克·希曼绊倒了,他在那里写作

如果实体的ID彼此相等,则它们是相等的

当然,现在我想知道哪种方法更好


编辑:请注意,问题不是同时拥有同一实体的两个实例是否是一个好主意。我知道在大多数情况下可能不是这样。

我认为在不同的状态下拥有同一实体的两个独立实例是个坏主意。我想不出哪种情况是可取的。也许有一个?我相信一个给定实体应该只有一个具有特定ID的实例

一般来说,我会使用它们的ID来比较它们的相等性

但是,如果要检查它们是否为同一对象引用,则可以使用:

        if (Object.ReferenceEquals(entityA, entityB))
        {
            DoSomething();
        }

首先,实体不应该这样比较。没有有效的用例(在测试之外,但是断言库应该再次为您处理)来使用对象的Equals方法查看两个实体是否相等

使实体唯一的是它的Id。Id的目的是说明“尽管具有相同的属性/值,但该实体与其他实体不同”

也就是说,在一个域中,您可能需要将一个概念实例与另一个实例进行比较。比较是根据特定于有界上下文(甚至聚合)的域规则进行的。涉及实体并不重要,它也可能是一个值对象

基本上,“比较”应该是一个域用例,它可能会作为服务实现。这与对象的
Equals
方法无关,这是一个技术方面


在进行DDD时,不要像程序员(即技术方面)那样思考,也不要像架构师(高级)那样思考。代码、编程语言等只是一个实现细节。

问题有两个方面。首先,你真正想知道的是

当我用X语言(或Y框架)编写域模型时,如何处理这些术语

例如,C#强制要求您定义的任何新概念都继承一个。Java包括

我从未听过领域专家谈论散列码或实例平等,但这是Evans apply(经常被误解)引用的“不要对抗框架”的情况之一:只要教开发人员在不属于领域接口时不要使用它们

那么,你想知道的是

什么是实体?它与自己的身份有什么关系

从为什么开始!您知道实体是普遍存在的语言中可以识别的术语

但是为什么呢

简单明了:实体描述的概念,其在时间上的演化与我们正在解决的问题的上下文相关

定义实体的是进化的相关性,而不是相反!身份只是一种沟通工具,用来跟踪进化,谈论进化

举个例子,想想你:你是一个有名字的人;我们用你的名字来交流你在生活中与世界其他地方的互动;不过,你不是那个名字

问问自己:为什么我需要比较域实体领域专家是这样说的吗?或者我只是用DDD术语来描述与关系数据库交互的CRUD应用程序?

对我来说,需要实际实现
Equals(object)
GetHashCode()
进入一个实体看起来有一股基础设施不足的味道。

为什么同一实体处于两种不同的状态?同一实例怎么可能同时处于不同的状态?@marianoc84这可能发生在桌面应用程序中,例如,在桌面应用程序中,对象通常比web应用程序中的对象寿命更长。用户可以更新内存中的某个实体,然后从数据库中再次读取该实体将返回旧版本。@RoumelisGeorge当然,它们不会是同一个实例,否则整个讨论将没有多大意义。因此,您的问题是,是否应将过期实体视为与更新版本相同的实体。我认为一个实体是通过定义它的id来定义的。我同意有两个相同实体的实例是不可取的。但是,为什么要费心创建一个通过ID进行比较的Equals实现呢?我认为这样做的原因是在比较值对象和实体时对它们进行区分。例如,当比较值对象时,如:
if(vo1==vo2)
,则应比较其属性的值。但是如果您对实体执行了相同的操作:
if(e1==e2)
则它应该检查ID。如果您没有实现equals覆盖,那么调用的开发人员需要知道是否根据对象类型(实体或值)手动检查ID或属性值。但是通过实现覆盖,他们不需要担心。现在这个答案包含了一些透彻的推理,这就是我想要的+1、你能解释一下“基础设施不足的味道”是什么意思吗?如果你愿意回答,我在这里问了一个类似的问题:“@w0051977很好地总结了我的观点。我区分dll中的契约(实体接口、异常、值对象、域服务接口)、实现(e