2

我想通过 JPA 存储树结构。该模型由两个实体类组成:TreeVertex。类Vertex基本上只包含顶点的名称,类Tree是一个名为的映射parents,它存储每个子顶点的父顶点(child -> parent)。

这种结构使我可以简单快速地访问给定子顶点是否具有父顶点以及实际父顶点(如果有)的信息。

我使用以下注释来指定 JPA(在我的例子中为 EclipseLink)应如何存储关系:

@MapKeyClass(Vertex.class)
@MapKeyJoinColumn(name = "child_id", nullable = false)
@OneToMany(targetEntity = Vertex.class, cascade = CascadeType.ALL)
@JoinTable(name = "bug_492_tree_parents", inverseJoinColumns = { @JoinColumn(name = "parent_id") })
private final Map<Vertex, Vertex> parents = Maps.newHashMap();

不幸的是,使用上面的映射,我无法存储具有相同父级的两个子顶点,例如V = {parent, child1, child2}and E = {{child1, parent}, {child2, parent}}(因此,child1 -> parentand child2 -> parent),因为我得到了完整性约束违规:

Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '3-4' for key 'PRIMARY'
Error Code: 1062
Call: INSERT INTO bug_492_tree_parents (parent_id, tree_id, child_id) VALUES (?, ?, ?)

这是由 JPA / EclipseLink 如何指定连接表中的主键引起的:

主键定义不正确

不幸的是,EclipseLink 选择了复合键(tree_id,parent_id)作为主键。使用这个主键,不可能存储任何包含两个不同子顶点且父顶点相同的树,如上述简单示例中所示。

只有在手动修复主键(在 MySQL 数据库模式中)之后,(tree_id,child_id)我才能存储该树:

固定主键

我尝试了许多不同的映射;但是,我总是遇到一些(其他)问题。

最后,我的问题是:我应该或可以如何通过 JPA 存储那个简单的树结构?我必须选择不同的映射吗?我必须改变我的模型吗?

4

1 回答 1

0

我不认为 JPA 可以做你想做的事情。

当将 Map 放入时,一个名为 E JPA 的实体希望您希望使用 V 的某个属性作为地图的 K,并在 E 和 V 之间而不是在 K 和 V 之间建立 OneToMany 关系。

最简单的解决方案是忘记您的 Map 并将 aList<Vertex>放入仅包含顶部节点的类中,并将 aList<Vertex>放入 Vertex 类中以用于顶点之间的子父关系。

如果您想要一个更像现在的结构,我认为您将不得不引入一个额外的实体,例如:

@Entity
VertexRelation {
    private Vertex parent;
    private Vertex child;
    ...
}

然后你的 Map 可以变成 aMap<Vertex, VertexRelation>并且你可以@MapKey(name="parent")用来告诉 JPA 你想使用 parent 作为地图的键。

注意:使用附加实体只是一个想法,我自己从未尝试过。我总是使用类似于我对树木的第一个建议的东西。

于 2012-08-19T07:23:09.220 回答