I have the following entitties:
@MappedSuperclass
public abstract class Node<Type> {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent")
@Nullable
@NaturalId
@OnDelete( action = OnDeleteAction.CASCADE)
protected Type parent;
@Column
private Integer pos;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "parent", insertable = false, updatable = false)
@OrderColumn(name = "pos")
private List<Type> children;
}
@Entity
public class NodeImpl extends Node<NodeImpl> {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToOne(cascade = CascadeType.MERGE)
@JoinColumn(name = "value_id")
@NaturalId
private Value value;
@ManyToOne(fetch = FetchType.LAZY)
@NaturalId(mutable = true)
private Owner owner;
}
@Entity
public class Owner {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "node_id")
private NodeImpl node;
}
I load an Owner instance then I prefetch the whole tree using the following JPQL query:
select n from NodeImpl n
join fetch n.children nc
join fetch n.value nv
where n.owner = :owner
Now the whole tree is loaded in entity manager so no extra db queries should be used when traversing owner's node hierarchy. This works fine for middle nodes, but for each leaf node a query is issued:
select ...
from node children_
left outer join value value_ on children_.value_id=value_ .id
where children_.parent=?
It seems that the leaf's empty children is treated as "unloaded" and triggers a db query. |