Search code examples
javahibernate-4.x

Get lazy children set by Criteria


I have a Parent class and a Child class with the current setup

@Entity
public class Parent {
   @OneToMany(mappedBy = "parent")
   private Set<Child> children;

   @Column
   private int type;
}

@Entity
public class Child {
   @ManyToOne
   @JoinColumn(name = "parent_id")
   private Parent parent;
}

For some functions, I want to when querying the parent based on its type, the child is automatically retrieved and filled into the set.

This is what I have tried so far

res = getSession().createCriteria(
   Parent.class, "parent"
).createAlias(
   "parent.children", "children"
).add(
   Restrictions.eq("parent.type", type)
).setFetchMode(
   "children", FetchMode.JOIN // FetchMode.SELECT
).list();

When I run the unit test, the getter is always equals to Null (I do have data and relationship in database)

Parent parent = new Parent();
parent.setType(ParentType.WEEK);
parentDao.save(parent);

Child child = new Child();
child.setParent(parent);
childDao.save(child);

List<Parent> res = parentDao.findByType(0, 10, ParentType.WEEK, true);

assertNotNull(res.get(0).getChildren());
assertEquals(1, res.get(0).getChildren().size());

How can I fix this ?


Solution

  • You're creating a parent, wil a null children list, and persisting it. The Parent instance is thus stored in the first-level cache.

    Then you're creating a child and persist it.

    Then you're executing a query that retrieves the parent you've just created. Hibernate thus gets the ID from the database, sees that the ID is one of a Parent entity that is already in the cache, and thus returns that Parent instance. And since you' have not set its children list, it's still null.

    It's your responsibility to maintain the coherence of the entity graph in memory. Hibernate only cares about the owning side of the association. By setting a child's parent, but not adding the child to the parent's children, you have introduced an incoherence in the graph of entities. Everything will be fine in database because the owning side of the association is correctly initialized.

    If you start a new transaction and execute the query, the children list will be correctly populated. Similarly if you clear the session before executing the query. But inside the same transaction, Hibernate doesn't automagically initialize one side of the association when you initialize the other.