我对JPA / Hibernate(一般的Java)都很陌生,所以我的问题如下(请注意,我已经进行了广泛的搜索并且没有找到答案):
我有两个实体:
父母和子女(命名已更改)。
父级包含儿童和儿童的列表,指回父母。
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;
/* ..... */
}
我希望能够做到以下几点:
检索一个父实体,其中包含所有子项的列表(List),但是,当列出Parent时(获取List,它当然应该省略结果中的子项,因此设置FetchType.LAZY。< / p>
检索包含Parent实体实例的Child实体。
使用上面的代码(或类似代码)导致两个例外:
检索父级: 在对象图中检测到循环。这将导致无限深的XML ......
检索孩子: org.hibernate.LazyInitializationException:懒得初始化角色集合:xxxxxxxxxxx,没有会话或会话关闭
检索Parent实体时,我使用的是命名查询(即专门调用它) @NamedQuery(name =“Parent.findByParentId”,query =“SELECT p FROM Parent AS p LEFT JOIN FETCH p.children其中p.id =:id”)
获取父级的代码(即服务层):
public Parent findByParentId(int parentId) {
Query query = em.createNamedQuery("Parent.findByParentId");
query.setParameter("id", parentId);
return (Parent) query.getSingleResult();
}
为什么我得到一个LazyInitializationException事件虽然Parent实体上的List属性设置为Lazy(检索Child实体时)?
答案 0 :(得分:1)
例外1.您的XML序列化与JPA / Hibernate没有任何关系,您将能够成功序列化双向设置。如果自动序列化失败,则以这样的方式预处理您的待序列化对象,即在事务之外删除从子节点到父节点的链接(假设您在容器中有自动合并)。
例外2.您应该阅读交易。简而言之,有些规则可以在何时完成需要数据库交互的对象的遍历。逻辑上,这种鸿沟必须存在。如果您希望延迟关系在事务会话之外表现为“正常”(读取:获取),则可以通过遍历或访问关系来简单地“预取”关系,以便解决关系。例如,在集合或列表上调用.size或迭代成员将执行此操作。
答案 1 :(得分:0)
<强> ADDED 强>
你的映射有点奇怪。您的映射描述的是两个不同的方向Releation发货:
这两者都是独立的,但存储在同一个数据库列中。
我想这不是你想要的,我想你想拥有一个双向关系。最简单的方法是更改Parent的子集映射,使用mappedBy
而不是@JoinColumn
:
@Entity
public class Parent {
...
/* fetch = FetchType.LAZY is default in one:many */
@OneToMany(cascade = { CascadeType.ALL }, mappedBy="parent")
private Set<child> children;
...
}
根据我在旧答案的评论中所描述的,这应该可以解决问题。因为如果你现在naviagate Parant - &gt;孩子 - &gt;父级,父级都是相同的,持久性提供者也知道它。
请注意,现在这种关系只能维持在孩子身边。
<强> OLD 强>
当你得到LazyInitializationException
时,问题是未加载的实体不再附加到EntityManager。在大多数情况下,问题是在加载实体之前关闭了事务。
你可以做的事情:
答案 2 :(得分:0)
我遇到了同样的问题。实际上我有一个单向关系(exp:Department有很多Employee)。因此,员工将拥有部门的外键。 生成后,Hibernate与ManyToOne和OneToMany建立双向关系。 因此,检查天气你的关系是单向还是双向。在第一种情况下,您需要删除映射oneToMany(来自Department)
希望它会有所帮助。