5

态关联类似于外键或多对一关系,不同之处在于目标可能是多种类型之一(语言中的类,数据库中的表)。

我正在将我多年来一直使用的数据库设计从 PHP 移植到 Java。在旧代码中,我推出了自己的 ORM,由于多种原因,这并不是最优的。虽然我可能稍后会开始调整,最终可能会再次自己实现,但现在我想在我的实体类上使用现成的 ORM 和 JPA。

现在,关于数据库布局的一件事我不知道如何在 JPA 中表达:

我有一个Node和一个Edge存储图表的表格(一个 DAG,如果重要的话)。每个节点可以选择性地引用数据库中的另一个实体。这些实体可能在整个图表中被多次引用,也可能存在“孤立”实体,用户无法访问这些实体,但至少保留一段时间可能是有意义的。

这些对象在继承等方面完全不相关,但具有自然层次结构,类似于 Customer->Site->Floor->Room。事实上,几年前,我一开始只使用指向“父”对象的外键字段。但是,这种层次结构不够灵活,并开始分崩离析。

例如,我想允许用户在文件夹中对对象进行分组,一些对象可以有多个“父母”,而且关系也会随着时间而变化。我需要跟踪过去的关系,所以图的边有一个与之关联的时间跨度,它说明了从什么时候到什么时候那个边是有效的。

从节点到对象的链接存储在节点表的两列中,一列带有外部表中的 id,一列带有其名称。例如(省略了一些列):

table Node:
+--------+-------+----------+
| ixNode | ixRef | sRefType |
+--------+-------+----------+
|    1   |  NULL |   NULL   |  <-- this is what a "folder" would look like
|    2   |   17  |  Source  |
|    3   |   58  |  Series  |  <-- there's seven types of related objects so far
+--------+-------+----------+

table Source (excerpt):
+----------+--------------------+
| ixSource |        sName       |
+----------+--------------------+
|    16    | 4th floor breaker  |
|    17    | 5th floor breaker  |
|    18    | 6th floor breaker  |
+----------+--------------------+

可能有与使用 JPA 不同的解决方案。我可以更改表格布局或引入新表格等。但是,我已经考虑了很多,表格结构对我来说似乎还可以。也许还有第三种我没有想到的方式。

4

4 回答 4

5

我想你已经找到了答案。创建一个抽象类(@Entity 或@MappedSuperclass)并让不同的类型对其进行扩展。

像这样的东西可能会起作用

@MappedSuperclass
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class Edge { 
    // . . .
    @OneToMany
    Collection<Node> nodes; 
}

@Entity 
public class Source extends Edge { 
}

@Entity public class Series extends Edge { 
}

@Entity
public class Node { 
    // . . .
    @ManyToOne
    Edge edge; 
}

我知道您可能不想暗示 Source 和 Series 之间的关系,但是扩展一个通用的抽象(无表)类是我能想到的做您想做的唯一方法。

InheritanceType.TABLE_PER_CLASS 将 Source 和 Series 保存在单独的表中(您可以使用 SINGLE_TABLE 来执行与上一个答案类似的操作)。

如果这不是您想要的,许多 JPA 提供程序提供了一个工具,该工具可以基于现有的一组表创建映射。在 OpenJPA 中,它被称为 ReverseMappingTool [1]。该工具将生成 Java 源文件,您可以将其用作映射的起点。我怀疑 Hibernate 或 EclipseLink 有类似的东西,但您可以只使用 OpenJPA 并使用具有不同提供程序的实体定义(据我所知,该工具不会生成任何 OpenJPA 特定代码)。

[1] http://openjpa.apache.org/builds/latest/docs/manual/manual.html#ref_guide_pc_reverse

于 2009-06-30T02:27:17.200 回答
5

答案是:

  • 继承(正如 Mike 已经建议的那样)
  • 加上@DiscriminatorColumn提供信息,哪个列存储有关应该使用哪个子类的信息:sxRef。我看到的唯一疑问是“sxRef”是一个可为的列。我想这是被禁止的。
于 2009-07-03T12:51:21.270 回答
2

你看过@Any注解吗?它不是 JPA 的一部分,而是它的 Hibernate Annotation 扩展。

于 2009-06-30T04:38:05.023 回答
0

Source 和 Series 表中存储了多少信息?它只是一个名字吗?如果是这样,您可以将它们组合到一个表中,并添加一个“类型”列。您的 Node 表将丢失其 sRefType,并且您将拥有一个如下所示的新表:

ixSource        sName                  sType
  16            4th floor breaker      SOURCE
  17            5th floor breaker      SOURCE
  18            6th floor breaker      SOURCE
  19            1st floor widget       SERIES
  20            2nd floor widget       SERIES

此表将替换 Source 和 Series 表。Source 和 Series 都属于超类吗?这将是该表的自然名称。

于 2009-06-26T16:00:50.923 回答