JPA:如何拥有相同实体类型的一对多关系 [英] JPA: How to have one-to-many relation of the same Entity type

查看:43
本文介绍了JPA:如何拥有相同实体类型的一对多关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有一个实体类A".A 类可能有相同类型A"的孩子.如果它是一个孩子,A"也应该持有它的父母.

There's an Entity Class "A". Class A might have children of the same type "A". Also "A" should hold it's parent if it is a child.

这可能吗?如果是这样,我应该如何映射实体类中的关系?[A"有一个 id 列.]

Is this possible? If so how should I map the relations in the Entity class? ["A" has an id column.]

推荐答案

是的,这是可能的.这是标准双向 @ManyToOne/@OneToMany 关系的特例.它很特别,因为关系两端的实体是相同的.JPA 2.0 规范的第 2.10.2 节详细介绍了一般情况.

Yes, this is possible. This is a special case of the standard bidirectional @ManyToOne/@OneToMany relationship. It is special because the entity on each end of the relationship is the same. The general case is detailed in Section 2.10.2 of the JPA 2.0 spec.

这是一个有效的例子.一、实体类A:

Here's a worked example. First, the entity class A:

@Entity
public class A implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
    @ManyToOne
    private A parent;
    @OneToMany(mappedBy="parent")
    private Collection<A> children;

    // Getters, Setters, serialVersionUID, etc...
}

这是一个粗略的 main() 方法,它保留了三个这样的实体:

Here's a rough main() method that persists three such entities:

public static void main(String[] args) {

    EntityManager em = ... // from EntityManagerFactory, injection, etc.

    em.getTransaction().begin();

    A parent   = new A();
    A son      = new A();
    A daughter = new A();

    son.setParent(parent);
    daughter.setParent(parent);
    parent.setChildren(Arrays.asList(son, daughter));

    em.persist(parent);
    em.persist(son);
    em.persist(daughter);

    em.getTransaction().commit();
}

在这种情况下,所有三个实体实例都必须在事务提交之前持久化.如果我未能在父子关系图中持久化实体之一,则 commit() 将引发异常.在 Eclipselink 上,这是一个 RollbackException,详细说明了不一致之处.

In this case, all three entity instances must be persisted before transaction commit. If I fail to persist one of the entities in the graph of parent-child relationships, then an exception is thrown on commit(). On Eclipselink, this is a RollbackException detailing the inconsistency.

此行为可通过 A@OneToMany@ManyToOne 注释上的 cascade 属性进行配置.例如,如果我在这两个注释上设置 cascade=CascadeType.ALL,我可以安全地保留其中一个实体并忽略其他实体.假设我在我的交易中坚持了 parent.JPA 实现遍历 parentchildren 属性,因为它用 CascadeType.ALL 标记.JPA 实现在那里找到 sondaughter.然后它代表我坚持两个孩子,即使我没有明确要求.

This behavior is configurable through the cascade attribute on A's @OneToMany and @ManyToOne annotations. For instance, if I set cascade=CascadeType.ALL on both of those annotations, I could safely persist one of the entities and ignore the others. Say I persisted parent in my transaction. The JPA implementation traverses parent's children property because it is marked with CascadeType.ALL. The JPA implementation finds son and daughter there. It then persists both children on my behalf, even though I didn't explicitly request it.

还有一个注意事项.更新双向关系的双方始终是程序员的责任.换句话说,每当我将一个孩子添加到某个父级时,我必须相应地更新孩子的父级属性.仅更新双向关系的一侧是 JPA 下的错误.始终更新关系的双方.这是在 JPA 2.0 规范的第 42 页上明确写的:

One more note. It is always the programmer's responsibility to update both sides of a bidirectional relationship. In other words, whenever I add a child to some parent, I must update the child's parent property accordingly. Updating only one side of a bidirectional relationship is an error under JPA. Always update both sides of the relationship. This is written unambiguously on page 42 of the JPA 2.0 spec:

请注意,应用程序负责维护运行时关系的一致性——例如,当应用程序更新运行时的关系.

Note that it is the application that bears responsibility for maintaining the consistency of runtime relationships—for example, for insuring that the "one" and the "many" sides of a bidirectional relationship are consistent with one another when the application updates the relationship at runtime.

这篇关于JPA:如何拥有相同实体类型的一对多关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆