渴望获取嵌套(递归)对象 - Hibernate
Eager fetch nested (recursive) objects - Hibernate
我想急切地填充我的对象层次结构。问题是 Hibernate 在某些时候停止获取;它留下未填充的关系字段(列表)。
层次结构是(省略了一些代码,如 id、getter,这部分似乎没问题,希望如此):
public class User {
private Container container;
@OneToOne(fetch = FetchType.EAGER)
public Container getContainer() {
return container;
}
}
public class Container {
private List<Backpack> backpacks;
private List<Item> items;
@OneToMany(fetch = FetchType.EAGER, mappedBy="container")
@Fetch(FetchMode.SELECT)
private List<Item> getItems() {
return items;
}
@OneToMany(fetch = FetchType.EAGER, mappedBy="container")
@Fetch(FetchMode.SELECT)
private List<Backpack> getBackpacks() {
return backpacks;
}
}
public class Backpack {
...
private Container container; /* Unidirectional relationship - ID of container which contains this backpack */
private Container backpackContainer; /* Unidirectional relationship - ID of container which represents backpack's storge */
...
@NotNull
@ManyToOne(fetch = FetchType.EAGER)
@Fetch(FetchMode.SELECT)
public Container getContainer() {
return container;
}
@OneToOne(fetch = FetchType.EAGER)
@Fetch(FetchMode.SELECT)
public Container getBackpackContainer() {
return backpackContainer;
}
}
结果:
User(
uid=2,
name=admin,
....,
container=Container(
id=1,
items=[
Item(...),
Item(...),
Item(...),
Item(...)
],
backpacks=[
Backpack(
container=1,
backpackContainer=Container(
id=3,
items=null, /* Problem! Shouldn't be empty array [] at least or array with items? */
backpacks=null /* Problem! Shouldn't be empty array [] at least or array with backpacks? */
)
)
]
)
)
正如我注释的结果,嵌套字段项目和背包为空,这表明存在巨大问题。 Hibernate 倾向于使用空集而不是空集,我也不想到处添加空检查器。
什么会导致这个问题?
此外,这个层次结构不是无限深的,用户的容器可以有任意多个背包,但这些背包可能不包含另一个背包。
唯一合乎逻辑的解释是,您正在同一持久性上下文(会话)中读取 User
图,您在其中保存了一个新的(瞬态)Container
实例,其中包含已分配的空值之后加载和组装 User
图时参考 backpackContainer
。
Hibernate 在保存实例时不会填充关联,但它会在从数据库加载实例时填充关联,因此您使用空值创建它并且它在持久性上下文中仍然如此。当您之后阅读 User
图时,Hibernate 会重用持久性上下文中当前存在的所有内容,包括它分配给 backpackContainer
字段的 Container
实例。
所以,你有两个选择:
- 如果您确实打算在同一持久性上下文中使用双向关系的双方(更简洁的方法);
或者在读取 User
之前刷新并清除持久性上下文(如果您希望所有事情都发生在同一个事务中):
entityManager.flush();
entityManager.clear();
我想急切地填充我的对象层次结构。问题是 Hibernate 在某些时候停止获取;它留下未填充的关系字段(列表)。
层次结构是(省略了一些代码,如 id、getter,这部分似乎没问题,希望如此):
public class User {
private Container container;
@OneToOne(fetch = FetchType.EAGER)
public Container getContainer() {
return container;
}
}
public class Container {
private List<Backpack> backpacks;
private List<Item> items;
@OneToMany(fetch = FetchType.EAGER, mappedBy="container")
@Fetch(FetchMode.SELECT)
private List<Item> getItems() {
return items;
}
@OneToMany(fetch = FetchType.EAGER, mappedBy="container")
@Fetch(FetchMode.SELECT)
private List<Backpack> getBackpacks() {
return backpacks;
}
}
public class Backpack {
...
private Container container; /* Unidirectional relationship - ID of container which contains this backpack */
private Container backpackContainer; /* Unidirectional relationship - ID of container which represents backpack's storge */
...
@NotNull
@ManyToOne(fetch = FetchType.EAGER)
@Fetch(FetchMode.SELECT)
public Container getContainer() {
return container;
}
@OneToOne(fetch = FetchType.EAGER)
@Fetch(FetchMode.SELECT)
public Container getBackpackContainer() {
return backpackContainer;
}
}
结果:
User(
uid=2,
name=admin,
....,
container=Container(
id=1,
items=[
Item(...),
Item(...),
Item(...),
Item(...)
],
backpacks=[
Backpack(
container=1,
backpackContainer=Container(
id=3,
items=null, /* Problem! Shouldn't be empty array [] at least or array with items? */
backpacks=null /* Problem! Shouldn't be empty array [] at least or array with backpacks? */
)
)
]
)
)
正如我注释的结果,嵌套字段项目和背包为空,这表明存在巨大问题。 Hibernate 倾向于使用空集而不是空集,我也不想到处添加空检查器。
什么会导致这个问题?
此外,这个层次结构不是无限深的,用户的容器可以有任意多个背包,但这些背包可能不包含另一个背包。
唯一合乎逻辑的解释是,您正在同一持久性上下文(会话)中读取 User
图,您在其中保存了一个新的(瞬态)Container
实例,其中包含已分配的空值之后加载和组装 User
图时参考 backpackContainer
。
Hibernate 在保存实例时不会填充关联,但它会在从数据库加载实例时填充关联,因此您使用空值创建它并且它在持久性上下文中仍然如此。当您之后阅读 User
图时,Hibernate 会重用持久性上下文中当前存在的所有内容,包括它分配给 backpackContainer
字段的 Container
实例。
所以,你有两个选择:
- 如果您确实打算在同一持久性上下文中使用双向关系的双方(更简洁的方法);
或者在读取
User
之前刷新并清除持久性上下文(如果您希望所有事情都发生在同一个事务中):entityManager.flush(); entityManager.clear();