【问题标题】:Hibernate, SQL and recursive associationsHibernate、SQL 和递归关联
【发布时间】:2010-06-23 14:12:52
【问题描述】:

我的数据库有两个表,“问题”和“字段”。问题可能有很多字段,字段可能有很多字段。这是一棵具有特殊根节点的树。

我想将它们与 hibernate(目前是 potgresql)一起使用 - 所以从 java 中使用它应该简单明了。

什么是最好的解决方案?

  1. 将 question_parent_id 和 field_parent_id 添加到“字段”表中,并且仅当 question_parent_id 是它的直接后代时才使用它。 (检查 XOR 哪个 SQL 约束...可能取决于 SQL 服务器)
  2. 添加 question_parent_id 和 field_parent_id,并始终使用 question_parent_id。请记住保持一致...(question_id 不应更改,可能不是真正的风险)
  3. 使用postgresql特定的表继承:“问题”和“字段”扩展“内容”,所以一个外键列就足够了。对“问题”和“字段”使用附加约束。
  4. 使用第三个表(称为“容器”),仅包含一个 ID。容器可能有很多字段,一个字段可能有一个容器。问题只有一个容器。但这需要 java 中的额外代码,并且存在无限循环的风险,即使在 field_container_id 上使用唯一键...

【问题讨论】:

  • 我在答案中添加了更多段落。您需要提供一些更具体的信息才能获得具体的答案。 (如果您发现有特定的要求,请考虑提出一个新问题。)

标签: java sql hibernate orm tree


【解决方案1】:

我宁愿考虑类模型而不是关系模型。最后的用户(通常)不关心您的数据库中有多少键。他正在使用您的课程,它应该“简单易用”。所以先写你的类模型,然后再考虑映射。

数据库中的解决方案取决于你的类模型。

编辑:另一边的模型取决于您需要做什么。

导航:您通常需要问题中的所有字段吗?您通常只需要直接分配给问题或字段的字段,还是递归地沿树向下分配所有字段?您需要知道字段的父级吗?等等等等。

查询:您是否需要按分配给它们的字段过滤问题或字段?递归?您需要按父项过滤字段吗?等等

换句话说:您无法针对所有内容进行优化。有典型的查询和典型的导航路径。支持太多方式可能会变得昂贵,并且可能需要模型和数据库中的冗余数据,这使得维护变得困难。

【讨论】:

  • +1 尊重客户端代码作为最终用户,以推出最佳设计。 :)
【解决方案2】:

除非我遗漏了什么,否则[Question][Field] 之间存在一对多关系(这是一对多,对吗?),并且之间存在自引用的一对多关联[Field]。所以我会:

  • question_id 添加到[Field] 表中以获取前一个关系
  • parent_id 添加到[Field] 表中以用于后面的关系

Hibernate 可以毫无问题地映射它。

【讨论】:

  • @Dutow 是的,但我看不出区别(这对你来说一定很明显:)
  • in #1: question.fields[x].question_id != NULL && question.fields[x].fields[y].question_id == NULL 对于每个 x 和 y 始终为真。在 #2 question.fields[x].question_id != NULL && question.fields[x].fields[y].question_id != NULL 对于每个 x 和 y 始终为真。 (#2 可能不一致:fields[x].fields[y].parent_id != fields[x].parent_id)
  • @Dutow:哦,我明白了。 #1 更接近您当时描述的内容(只有根字段有 question_id)。
【解决方案3】:

如果您想要一个高性能的解决方案,您必须仔细考虑您的层次结构有多深。这种递归结构对于 hibernate 加载来说可能非常昂贵,因为它通常最终会为每个字段创建大量连接,因为它可能有子字段(并且它们可能有子字段等)

如果您希望允许无限深度,但您总是希望加载整个问题,包括所有字段和子字段。然后我建议 Field 有一个父字段(可为空)和一个拥有问题(不可为空)。这使您可以使用以下 HQL 有效地加载整个问题:

SELECT q FROM Question q
JOIN FETCH q.allFields

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-25
    • 1970-01-01
    • 2010-12-11
    • 2017-08-14
    • 1970-01-01
    相关资源
    最近更新 更多