繁体   English   中英

在equals和hashcode方法中使用自动生成的Hibernate实体对象的id

[英]Using auto generated id of Hibernate entity object in the equals and hashcode methods

可爱的等号和哈希码,所有的理论都在这里 ,也在这里

我已经决定在我的许多hibernate实体/域对象中使用equals()和hashcode()中的自动生成的id。

但是,许多网站都说你不应该这样做,因为在比较或使用哈希码的过程中,第一次将对象持久存在数据库的风险。

我的观点是,在大多数用例中,这比任何其他字段更改都要小得多。

单个域对象在首次创建时会生成一次id,而几乎所有其他字段都有机会在正常业务流程中进行更改(即使可以更改唯一的用户名......)。

在我的许多域对象中,唯一的id几乎是唯一合适的字段(Person,Address,Pet,... Customer等等??组合字段是一个好主意,但从使用自动生成的id,我想,不是很好的建议。

我错过了别的什么吗?

您应该在Hibernate Community Wiki上阅读Equals和HashCode

不使用equals的数据库标识符的主要原因,并且暗示, hashCode用于处理存储的但不是持久的实体。 在持久化之前,所有实例都是equal ,除非您注意明确处理该情况。

如果你知道你不会参与这种情况,而且你确保它有很好的文档记录,你可能会很好。 您可以随时更改实施。

不,我认为你没有遗漏任何根本的东西。 使用equals和hashCode的数据库ID问题的“根本原因”是Hibernate生成的ID存储在可变字段中,当Hibernate分配ID时,该字段的值会发生变化。 Equals和hashCode应该基于不可变状态,如Odersky / Spoon / Venners关于编写equals / hashCode方法的文章中描述的“陷阱#3”。 这意味着,除了其他事项之外,您无法将实例添加到Set或将其与另一个实例进行比较,直到它被保持为止,当hashCode变为固定时。

您可能唯一缺少的是跟踪ID何时被分配是多么棘手,因为它是由Hibernate自动完成的。 当然,您可能永远不会调用setId(someNewId) ,但您可能会发出一个触发会话刷新的查询,并且与查询无关的一大堆瞬态实体突然将其ID从null更改为非null。

Hibernate社区通常建议使用equals和hashCode的业务键,但这种方法也会遇到相同的可变直到初始化问题。 如果您的实体是Hibernate急切加载的持久集的成员,那么它可以在其字段初始化之前添加到集合中,因此基于这些字段的hashCode也不起作用。 请参阅此Hibernate错误报告,讨论业务密钥相等的问题。

James Brundege 建议在应用程序代码中分配ID以避免此问题。 Lance Arlaus使用一个分配ID的对象工厂也有类似的方法

如果您真的想为equals和hashCode使用自动生成的ID,请考虑在equals和hashCode的实现中使用Assert.notNull(id)来检测编码错误。

另请参阅另一个stackoverflow 问题,其中包含对不同方法的大量讨论。

我遇到了auto-id-generation的equals问题,因为我根据新的用户输入创建了我的对象。 所以我没有明确地比较它们或者什么,我只是将它们放入Set中。 那时它已经失败了,因为Set依赖于equals()/ hashCode()(它再次基于对象id,因为我没有其他选项)。

然后我将其更改为实际生成和分配id我自己,这是更好的解决方案。

请阅读这篇文章,它准确地解释了这个问题: 不要让 - hibernate-steal-your-identity

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM