【问题标题】:Hibernate/JPA Parent-Child - is it okay for Parent equals()/hashCode() to use the DB Id?Hibernate/JPA Parent-Child - Parent equals()/hashCode() 可以使用 DB Id 吗?
【发布时间】:2023-03-18 00:08:02
【问题描述】:

鉴于以下情况:

@Entity
public class Parent implements Serializable {
  @Id
  private Long id;
  // mapped ManyToOne below...
  private List<Child> children = new ArrayList<Child>();

  ...

}

让 Parent.equals() 和 Parent.hashCode() 只使用 id 是不是一种不好的做法?我知道 Child.equals() 和 Child.hashCode() 应该使用一组不可变的属性作为“自然键”,以便它们由 Parent 正确管理。但是,如果 Parent 始终是顶级对象(即它永远不是任何关联的反面),那么仅使用 id 有什么问题吗?

是否有任何不良影响可以通过这样做来表现出来?我猜也许如果我这样做,当我添加一个孩子(或删除)时,Hibernate 将无法告诉 Parent 已经改变(并且需要在 DB 中更新)?在这种情况下,我应该为 Parent.equals() 和 Parent.hashCode() 使用 children 属性吗?

我之所以问是因为 Hibernate 文档明确表示不要将 @Id 属性用于“自然键”...

【问题讨论】:

    标签: java hibernate jpa jakarta-ee


    【解决方案1】:

    使用 ID 作为 equals 和 hashCode 基础的主要问题是未持久化的对象。这些对象可能都以相同的 ID 开头,并且无法正确比较是否相等。即使您从未将对象放入集合中,如果它们通过 API 公开并且其他人可以创建它们的实例并将它们放入集合中,那么您已经向一些讨厌的错误敞开了大门。

    【讨论】:

    • 我明白你在说什么,但从技术上讲,如果 id 为零,那么它们实际上是相等的:它们都是未持久的 Parent 对象。对于上面只有这两个属性(id 和 children)的示例,您建议如何实现 equals() 和 hashCode()?我需要介绍更多属性吗?
    • 即使不涉及 Hibernate,您是否可以在用于 equals() 和 hashCode() 的字段上允许修改器?有人可以在 HashSet 中放置一个实例,更改影响哈希码的字段,并以这种方式破坏集合。但禁止它似乎有点苛刻。我倾向于你必须分别考虑每种情况并权衡利弊......
    • @Greenie:如果我从另一个来源导入数据,我可能会创建一个完整的新对象图,在持久化它们并刷新休眠之前,我必须将其存储在某个地方。仅仅因为他们有 ID 0 并不意味着他们是平等的,这意味着他们还没有一个 ID。
    • @Waxwing:是的,如果你将一个对象放入一个哈希集中,然后更改一个导致其哈希更改的属性,那么你已经破坏了 set.contains()。正确的回答是 a) 不要那样做,或者 b) 确定如果你那样做,你就知道后果。这是您为使用非不可变对象所付出的代价。
    • @Jherico:非常好的观点。我仍在等待有关如何正确实现它的建议,以及是否应该在 equals() 和 hashCode() 中使用 children 属性的问题的答案。
    猜你喜欢
    • 1970-01-01
    • 2011-05-10
    • 2014-04-05
    • 1970-01-01
    • 1970-01-01
    • 2016-03-22
    • 2018-03-12
    • 1970-01-01
    • 2018-01-02
    相关资源
    最近更新 更多