Reputation: 3070
I want to populate my object hierarchy eagerly. The problem is that at some point Hibernate stops from fetching; it leaves relation fields (lists) unpopulated.
The hierarchy is (some code is ommited like id's, getters, this part seems to be fine, hopefully):
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;
}
}
And the result:
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? */
)
)
]
)
)
As I annotated the result, nested fields items and backpacks are null, which suggests a huge problem. Hibernate tends to use empty sets instead of nulls, also I don't want to add null checkers everywhere.
What can cause this problem?
Also, this hierarchy is not infinite-deep, user's container may have as many backpacks as it wants, but those backpacks may not contain another backpacks.
Upvotes: 0
Views: 1863
Reputation: 23552
The only logical explanation is that you are reading the User
graph in the same persistence context (session) in which you have saved a new (transient) Container
instance containing nulls which is assigned to the backpackContainer
reference when loading and assembling the User
graph afterwards.
Hibernate does not populate the associations when saving instances, but it does it when loading instances from the db, so you created it with nulls and it remained such in the persistence context. When you read the User
graph afterwards, Hibernate reuses everything that is currently present in the persistence context including the Container
instance which it assigns to the backpackContainer
field.
So, you have two choices:
Or simply flush and clear the persistence context before reading the User
(if you want everything to happen in the same transaction):
entityManager.flush();
entityManager.clear();
Upvotes: 2