Current stack:
- Spring Boot 1.5.1
- Spring Data JPA 1.11.0
- Hibernate Core 5.2.6
Let's say we have the following @Entity
structure
@Entity
class Root {
@Id
private Long id;
@OneToMany
@JoinColumn(name = "root_id")
private Set<Child> children
}
@Entity
class Child {
@Id
private Long id;
@OneToMany
@JoinColumn(name = "child_id")
private Set<Grandchild> grandchildren;
}
@Entity
class Grandchild {
@Id
private Long id;
}
When I query for all/specific Root
objects Hibernate selects only from the corresponding table and the resulting objects' children
Set is a Hibernate proxy - as it should be.null
When I call getChildren()
Hibernate correctly initializes the collection but also (unwarrantedly) fetches each Child
object's grandchildren
Set.
Can someone please explain exactly why this recursive fetching is happening and is there a way to disable it?
I did some more digging and this is what I came up with: it seems to be related to the way Hibernate maps @OneToMany
depending on whether the target collection is a List
or Set
.
private final RootRepo repo;
If the collections are Set
s
public void test() {
List<Root> all = repo.findAll(); // SELECT root0_.* FROM root root0_
all.forEach(root -> {
System.out.println(root.getChildren() == null); // false
System.out.println(Hibernate.isInitialized(root.getChildren())); // false
root.getChildren().forEach(child -> {
// SELECT child0_.* FROM children child0_
// SELECT grandchild0_.* FROM grandchildren grandchild0_
System.out.println(child.getGrandchildren() == null); // false
System.out.println(Hibernate.isInitialized(child.getGrandchildren())); // true
child.getGrandChildren().forEach(grandchild -> {});
});
});
}
However, with List
s
public void test() {
List<Root> all = repo.findAll(); // SELECT root0_.* FROM root root0_
all.forEach(root -> {
System.out.println(root.getChildren() == null); // false
System.out.println(Hibernate.isInitialized(root.getChildren())); // false
root.getChildren().forEach(child -> {
// SELECT child0_.* FROM children child0_
System.out.println(child.getGrandchildren() == null); // false
System.out.println(Hibernate.isInitialized(child.getGrandchildren())); // false
child.getGrandChildren().forEach(grandchild -> {
// SELECT grandchild0_.* FROM grandchildren grandchild0_
});
});
});
}
I am a certifiable idiot.
I'm using Lombok to generate getters/setters and the like for my POJOs and its default implementation of @EqualsAndHashCode
annotation generates both methods taking into account every field.. including the subcollections.