【问题标题】:JPA entity model proposalJPA 实体模型提案
【发布时间】:2012-02-23 21:44:57
【问题描述】:

我正在尝试通过休眠使用 JPA2.0 设计一个实体模型。

我有一个这样的域:有很多餐馆,所以显然有一个餐馆实体。每家餐厅都有许多不同的菜肴供应,0 对多的餐厅可能供应相同的菜肴。每道菜都有多种食材,有些菜品会共用食材。每种成分都有几种营养成分,每种营养成分也可能被0对多的成分所拥有。

我正在苦苦挣扎,因为我什至不确定我的问题到底是什么,但我知道我错过了一些东西。我认为问题在于如何准确地执行域模型以及主键和 .equals/.hashcode 方法的含义。

最初我打算使用生成的代理键。每个实体都会有类似

@Id
@GeneratedValue
public Long id;

.equals 将测试除 id 之外的所有实体成员的相等性。例如,无论 Long id 的值如何,一家餐厅都是相等的,但它的 List 成员是否相等。 (当然 Dish 会一直调用 .equals 一直到营养的层次结构。)

所以当我给一个 DAO bean 一个餐厅时,我只希望它在数据存储中没有等效的餐厅(通过 .equals)时保持不变。但我想这将涉及一个相当费力的 jpql 调用,我觉得它既不优雅也不高效(如果我错了,请告诉我。我经常错...哈哈)。在此过程中,如果它遇到说已经在数据存储中的成分(但不是菜肴的一部分,因此是新持久的),它会将新菜肴与已经存在的成分相关联,而不是创建一个全新的(和逻辑上重复)成分。

我想得越多,在这个等级制度的更高层坚持下去听起来就越痛苦。

我开始研究组合键(通过@IdClass 或@EmbeddedId)的想法,该组合键本身将包含子成员。这似乎在层次结构中坚持更高的东西就像通过 id 查找和坚持如果我没有找到任何东西一样简单。但我对此很怀疑……这似乎不对。这意味着我正在创建实体,其中所有成员和实体本身以及复合键的一部分。

一些注意事项。营养素的数量相对有限。成分的空间是 {numOfNutrients}^{typesOfNutrients},可能相当大。当我们到达餐厅时,客户几乎不可能意外地建造一个重复的餐厅,因为空间真的很大。有一点我实际上并不关心数据存储中是否存在重复项,因为它不太可能发生。事实上,看看这是否会发生几乎会很有趣。也不是说餐厅的例子是人为的。我的真实域名在形式上是相似的。

对不起,漫无边际。我知道帖子里有很多想法。但我觉得它们都非常相关,我想一次将它们全部提出来。

有人可以提供一些魔法吗?

我知道这个帖子:A class that behaves like @Entity and @Embeddable 通常我会看到类似的情况,“除非在特殊情况下”,否则不要这样做。这就是我所说的其中一种情况。如果不是,那么使用它的合适情况到底是什么。

还要注意,一旦将餐厅放入数据库,它的表示是不可变的。我意识到这个人为的例子是不现实的,但我的领域就是这种情况。这让我觉得让所有成员成为复合键的一部分是要走的路....

【问题讨论】:

  • 我不明白“相等”部分。比如说餐厅 R1 和 R2,他们都提供菜肴 (D1,D2,D3)。那么,他们是平等的,不允许吗?但您确实说过“0 对多的餐厅可能提供相同的服务。”
  • 餐厅 R1 和 R2 是相等的,前提是它们都拥有完全相同的菜肴列表,这是通过检查所有菜肴的 .equals 来确定的。它在某种意义上是递归的。 R1:(D1,D1,D3)==R2:(D1,D2,D3),但是 R1(D1,D2,D3)!=R3:(D1,D6)。因此,一道菜可能由 0 家餐厅供应。

标签: hibernate jakarta-ee orm jpa-2.0


【解决方案1】:

Hibernate 不使用 equals 和 hashCode 来判断一个实体是否已经持久化。如果实体有 ID,则它是持久的。否则,它是新的。如果两个实体具有相同的 ID,则它们是相同的。 equals 方法仅用于在 your 代码中(而不是在 Hibernate 代码中)比较两个分离的实体,或将分离的实体与附加的实体进行比较。

如果实体存储在 Set 中,您还需要 equals 和 hashCode。

如果你真的需要一个 equals 和 hashCode 方法,使用子实体的集合来实现它们是一个非常糟糕的主意。您不仅需要加载一半的数据库才能调用它们,而且一旦您将一种成分添加到菜肴中,它的 hashCode 就会发生变化,这会“破坏”存储它的集合。

您应该使用实体的不可为空的不可变唯一功能字段来实现 equals 和 hashCode(餐厅名称、菜品名称、营养品名称)。并且绝对使用代理标识符。如果没有这样的字段,可以使用 ID。但只需确保在将实体存储到 Set 之前生成它。

【讨论】:

  • 啊我明白你关于加载一半数据库的意思......所以如果我在客户端上有一个餐厅层次结构(餐厅,所有成员都归结为营养素),我需要做一些查询来看天气我需要创建新的菜肴、配料和营养实体,或者用已经存在的实体替换它们。那是我的代码。那不是我可以让hibernate做的事情吗?
  • 没错。这一切都取决于用户界面。如果您使用选择框来选择菜肴的成分,您就知道这些成分已经存在,并且您知道它们的 ID。如果让用户输入成分名称,则必须在数据库中按名称搜索该成分,如果存在则使用找到的成分,如果不存在则创建新的成分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-03
  • 1970-01-01
  • 2017-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多