2012-02-24 103 views
5

我读Eric Evans的书约DDD和我有以下报价的问题。当你不应该使用这些属性时,你如何制定equals()方法?我正在使用JPA,并且我有一个唯一的id属性,但是只有在实际持久化后才能设置。所以你会怎么做?我已经实现了基于属性的equals方法,我明白你为什么不应该这样做,因为它在我的项目中失败了。在实体领域驱动设计

节约实体:

当对象是由它的身份来区分,而不是它的 的属性,使这种初级其在模型定义。保持类别定义简单并集中于生命周期连续性和 身份。定义一种区分每个对象的方法,而不管其形式或历史如何。警惕需要按属性匹配 对象的需求。定义一个操作,保证 为每个对象产生一个唯一的结果,可能通过附加一个保证唯一的 符号。的识别这个装置可以 来自外部,或者它可以是通过 和为系统创建一个任意的标识符,但它必须对应于身份模型中的 区别。该模型必须定义什么意思是 同样的事情。

http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215

+0

可能的复制,见http://stackoverflow.com/questions/5031614/the-jpa-hashcode-equals-dilemma – MRalwasser 2012-02-24 13:27:51

+0

的ID正常工作对我来说:http://stackoverflow.com/questions/7579404/using-auto-generated-id-of-hibenate-entity-object-in-the-the-the-the-the-the-and-hashcode-met – NimChimpsky 2012-02-24 14:54:06

回答

1

夫妇办法可能:

  • 使用业务键值。这是最符合“DDD标准”的方法。仔细查看域名和业务要求。例如,您的企业如何识别客户?他们是否使用社会安全号码或电话号码?如果基于纸张(无电脑),您的企业如何解决这个问题?如果没有自然的商业密钥,请创建代理。选择最终的商业密钥并在equals()中使用它。 DDD书中有一节专门讨论这个特定问题。

  • 对于案件时,有没有自然业务键,您可以生成UUID。这在分布式系统中也有优势,在这种情况下,您不需要依赖像数据库这样的集中式(并且可能不可用)资源来生成新的ID。

  • 还有一个选项可以仅仅依靠默认的equals()实体类。它会比较两个内存位置,并且在大多数情况下都足够了,因为Unit Of Work(Hibernate Session)持有所有实体(此ORM模式称为Identity Map)。这是不可靠的,因为如果你使用不局限于一个Hibernate的Session的范围内实体(思线程,分离的实体等)

有趣的是,“官方” DDD示例使用一个非常这将打破轻量级框架,其中每一个实体类是从Entity接口派生与一种方法:

boolean sameIdentityAs(T other) 
// Entities compare by identity, not by attributes. 
+0

假设实体是问题。我会用什么?直到现在,我依靠生成的ID。 – LuckyLuke 2012-02-24 13:31:37

+0

取决于你的域名,可能是问题本身的文本(在这种情况下,它可能是Value not Entity),但更可能是问题编号。真的取决于你的域名。 – Dmitry 2012-02-24 14:04:00

1

如果对象是不持久的呢,那么有没有在根据其属性比较两个对象的任何伤害?

我不知道为什么这个失败的项目,但在我的经验,基于属性几乎总是比较光滑的斜坡,如果你的属性并不是最终的。这意味着,现在有两个相同的对象,在某个时间后可能不相同。这真是太糟了。

鉴于大多数Java类与他们一起存取写,等于比较属性被认为是一个坏主意。

不过,我可能会先检查,看看是否ID字段不为空。如果它为空,我会回归属性比较。如果它不是空的,那就使用它,不要做任何其他事情。这有意义吗?

+2

这是一件很危险的事情。如果您在分配其ID之前将对象存储在HashSet中,则HashSet将被损坏。 – 2012-02-25 08:14:13

+0

当然。但是,那么,我会假设你会坚持这个对象来获得这个id。在这种情况下,我通常更喜欢获取返回的持久化对象并使用它。基本上,不要改变在平等检查中使用的对象的状态。 – Pavan 2012-02-25 11:15:28

+0

如果您根据其属性比较对象,那么它的行为就像是一个Value Object而非一个Entity。值对象和实体在DDD中具有完全不同的语义,因此您不应将实体相等性置于属性上。 – 2014-03-11 01:43:45

1

鉴于Person类具有属性namesurname。当21岁的人改名时,仍然是同一个人(等于true)? 如果你写出等于基础的属性,那么它不会是同一个人,所以在我看来,最好的方法是在他们的业务标识符(在整个实体生命周期中唯一且不可变)测试实体基础的平等。

0

另一种解决方案可能是在您的实体中使用UUID字段。

在这种情况下,您可以使用UUID作为主键或仅用于等于。

@Entity 
public class YourEntity{ 

    @Id 
    private String uuid = UUID.randomUUID().toString(); 

    // getter only... 

}