Hi all,
I encountered a defect when chaining join fetches. Since it works with two other JPA implementations, I consider it as a Hibernate defect. I prepared a test case according to the template but have not found any place for uploading it. Therefore, I submit it here inline (otherwise please tell me where I can submit it).
Code:
package acme.hibernatetest.entities;
import java.util.*;
import javax.persistence.*;
@Entity
public class Node {
@Id
private String name;
@OneToMany
private List<Node> children;
Node () {
// required for JPA
}
public Node(String name, List<Node> children) {
this.name = name;
this.children = new ArrayList<>(children);
}
public String getName() {
return name;
}
public List<Node> getChildren() {
return children;
}
}
Code:
package acme.hibernatetest.entities;
import java.util.UUID;
import javax.persistence.*;
@Entity
public class NodeRelation {
@Id
private String uuid;
@ManyToOne
private Node ancestor;
@ManyToOne
private Node descendant;
private int distance;
NodeRelation() {
// required for JPA
}
public NodeRelation(Node ancestor, Node descendant, int distance) {
uuid = UUID.randomUUID().toString();
this.ancestor = ancestor;
this.descendant = descendant;
this.distance = distance;
}
public String getUuid() {
return uuid;
}
public Node getAncestor() {
return ancestor;
}
public Node getDescendant() {
return descendant;
}
public int getDistance() {
return distance;
}
}
The test case
Code:
@Test
public void hhh123Test() throws Exception {
EntityManager entityManager = entityManagerFactory.createEntityManager();
// prepare data in separate transaction
entityManager.getTransaction().begin();
Node leafNode = new Node("Leaf", Collections.emptyList());
entityManager.persist(leafNode);
Node innerNode = new Node("Inner", Collections.singletonList(leafNode));
entityManager.persist(innerNode);
Node rootNode = new Node("Root", Collections.singletonList(innerNode));
entityManager.persist(rootNode);
entityManager.persist(new NodeRelation(rootNode, rootNode, 0));
entityManager.persist(new NodeRelation(rootNode, innerNode, 1));
entityManager.persist(new NodeRelation(rootNode, leafNode, 2));
entityManager.persist(new NodeRelation(innerNode, innerNode, 0));
entityManager.persist(new NodeRelation(innerNode, leafNode, 1));
entityManager.persist(new NodeRelation(leafNode, leafNode, 0));
entityManager.getTransaction().commit();
// clear all cached entities
entityManager.clear();
entityManager.getTransaction().begin();
// we don't care about the result here
List<NodeRelation> relations =
entityManager.createQuery("SELECT nr FROM NodeRelation AS nr LEFT JOIN FETCH nr.descendant d LEFT JOIN FETCH d.children", NodeRelation.class).getResultList();
// of interest is the Node with id "Inner" which has incorrectly 2 children (two times the same object)
Node n = entityManager.find(Node.class, "Inner");
Assert.assertNotNull(n);
Assert.assertEquals(1, n.getChildren().size());
entityManager.getTransaction().rollback();
entityManager.close();
}