如何在JPA中表达多态关联?

时间:2009-06-26 14:40:54

标签: jpa database-design modeling polymorphic-associations

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

我正在移植一个数据库设计,我已经使用了几年,从PHP到Java。在旧的代码中,我已经推出了自己的ORM,由于多种原因这不是最佳的。虽然我可能会在以后开始调整内容,也许最终会自己再次实现,现在我想在我的实体类中使用现成的ORM和JPA。

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

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

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

例如,我想允许用户将文件夹中的对象分组,某些对象可以有多个“父母”,并且关系也会随着时间而变化。我需要跟踪过去的关系,因此图的edegs有一个与它们相关的时间跨度,表明从何时到该边缘有效。

从节点到对象的链接存储在节点表的两列中,一个在外表中携带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 个答案:

答案 0 :(得分: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

答案 1 :(得分:5)

答案是:

  • 继承(已由Mike提出)
  • plus @DiscriminatorColumn提供哪些列存储有关应使用哪个子类的信息的信息:sxRef。我看到的唯一疑问是“sxRef”是可以为空的列。我想这是禁止的。

答案 2 :(得分:2)

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

答案 3 :(得分: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都属于超类吗?这将是这张桌子的自然名称。