本文介绍了JPA/休眠父母/子女关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对JPA/Hibernate(一般来说是Java)很陌生,所以我的问题如下(请注意,我进行了广泛搜索,没有找到答案)

我有两个实体:

父子(更改名称).

父级包含子级"列表,子级"返回父级.

例如

@Entity
public class Parent {

@Id
@Basic
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "PARENT_ID", insertable = false, updatable = false)
private int id;

    /* ..... */

    @OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
    @JoinColumn(name = "PARENT_ID", referencedColumnName = "PARENT_ID", nullable = true)
    private Set<child> children;

    /* ..... */

}

@Entity
public class Child {

@Id
@Basic
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "CHILD_ID", insertable = false, updatable = false)
private int id;

    /* ..... */

    @ManyToOne(cascade = { CascadeType.REFRESH }, fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "PARENT_ID", referencedColumnName = "PARENT_ID")
private Parent parent;

    /* ..... */

}

我希望能够执行以下操作:

  1. 检索一个Parent实体,该实体将包含其所有子代的列表(List),但是,在列出Parent时(获取List),它当然应该从结果中省略子代,因此设置FetchType.LAZY. /p>

  2. 检索将包含父实体实例的子实体.

使用上面的代码(或类似代码)会导致两个例外:

  1. 正在检索父项:在对象图中检测到一个循环.这将导致无限深的XML ...

  2. 正在检索孩子:org.hibernate.LazyInitializationException:无法延迟初始化角色集合:xxxxxxxxxxx,没有会话或会话被关闭

检索父实体时,我使用的是命名查询(即专门调用它) @NamedQuery(name ="Parent.findByParentId",query ="SELECT p FROM Parent AS p LEFT JOIN FETCH p.children where p.id =:id")

获取父级(即服务层)的代码:

public Parent findByParentId(int parentId) {
    Query query = em.createNamedQuery("Parent.findByParentId");
    query.setParameter("id", parentId);

    return (Parent) query.getSingleResult();
}

为什么将Parent实体上的List属性设置为Lazy(在检索Child实体时),为什么会出现LazyInitializationException事件?

解决方案

异常1.使用JPA/Hibernate,您的XML序列化没有任何内容,您将能够成功地序列化双向设置.如果自动序列化失败,请以某种方式预处理您要序列化的对象,以便在事务之外删除子级到父级之间的链接(假设您的容器中有自动合并).

异常2.您应该阅读事务.简而言之,有规则规定何时可以进行遍历需要数据库交互的对象,而不能进行遍历.从逻辑上讲,这种鸿沟必须存在.如果您希望懒惰的关系在事务会话之外表现为正常"(读取:已获取),则可以通过遍历或访问该关系以解决该关系的方式来简单地预取"该关系.例如,在集合或列表上调用.size或遍历成员,即可做到这一点.

I am quite new to JPA/Hibernate (Java in general) so my question is as follows (note, I have searched far and wide and have not come across an answer to this):

I have two entities:

Parent and Child (naming changed).

Parent contains a list of Children and Children refers back to parent.

e.g.

@Entity
public class Parent {

@Id
@Basic
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "PARENT_ID", insertable = false, updatable = false)
private int id;

    /* ..... */

    @OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
    @JoinColumn(name = "PARENT_ID", referencedColumnName = "PARENT_ID", nullable = true)
    private Set<child> children;

    /* ..... */

}

@Entity
public class Child {

@Id
@Basic
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "CHILD_ID", insertable = false, updatable = false)
private int id;

    /* ..... */

    @ManyToOne(cascade = { CascadeType.REFRESH }, fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "PARENT_ID", referencedColumnName = "PARENT_ID")
private Parent parent;

    /* ..... */

}

I want to be able to do the following:

  1. Retrieve a Parent entity which would contain a list of all its children (List), however, when listing Parent (getting List, it of course should omit the children from the results, therefore setting FetchType.LAZY.

  2. Retrieve a Child entity which would contain an instance of the Parent entity.

Using the code above (or similar) results in two exceptions:

  1. Retrieving Parent:A cycle is detected in the object graph. This will cause infinitely deep XML...

  2. Retrieving Child:org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: xxxxxxxxxxx, no session or session was closed

When retrieving the Parent entity, I am using a named query (i.e. calling it specifically) @NamedQuery(name = "Parent.findByParentId", query = "SELECT p FROM Parent AS p LEFT JOIN FETCH p.children where p.id = :id")

Code to get Parent (i.e. service layer):

public Parent findByParentId(int parentId) {
    Query query = em.createNamedQuery("Parent.findByParentId");
    query.setParameter("id", parentId);

    return (Parent) query.getSingleResult();
}

Why am I getting a LazyInitializationException event though the List property on the Parent entity is set as Lazy (when retrieving the Child entity)?

解决方案

Exception 1. Your XML serialization does not have anything with JPA/Hibernate, you will be able to serialize your two-way-setup successfully. If automatic serialization fails, preprocess your to-be serialized objects in such a way that you remove the link from child to parent - outside the transaction (assuming you have automatic merges in your container).

Exception 2. You should read up on Transactions. In short, there are rules to when traversal of objects requiring database interaction can be done and not. Logically this divide must exist. If you want lazy relationships to behave as 'normal' (read: fetched) outside the transaction session, you simple 'prefetch' the relationship by traversing or accessing it in such a way that the relationship is resolved. For example call .size, or iterating over the members, on a set or a list will do this.

这篇关于JPA/休眠父母/子女关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 07:57