且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

JPA/休眠父母/子女关系

更新时间:2022-10-20 11:34:38

异常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.