0

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 ?

Thai Tran
  • 9,815
  • 7
  • 43
  • 64
  • What is equal to null? How could getChildren(), which I assume returns a `Set`, be equal to 1? – JB Nizet May 31 '14 at 07:45
  • ouch, not enough coffee for today!!! I edited my question. Thank @JBNizet – Thai Tran May 31 '14 at 08:00
  • The above code should work fine, unless the parent you're loading is a parent that you've just created, in the same transaction, and you have neglected to initialize its children list to something other than null. Hibernate will NEVER initialize a collection to null. And you should NEVER do it either. – JB Nizet May 31 '14 at 08:02
  • `unless the parent you're loading is a parent that you've just created, in the same transaction,` Exactly what it is. I created the parent and the child in the same unit test and then find it back (please have a look at complete test case - just edited). If I remove the saving part and use the old database, then it works. Thank you very much. You can make your comment into answer if you like @JBNizet – Thai Tran May 31 '14 at 08:21

1 Answers1

1

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.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255