Hibernate OneToOne lazy loading and cascading

Holm picture Holm · Jun 9, 2011 · Viewed 19.5k times · Source

Here's what I'm trying to do.

  1. Create a parent with a OneToOne relation to a child
  2. The parent has to fetch the children using lazy loading
  3. If parent is removed, so is the child
  4. If the child is removed, the parent should not be affected
  5. The cascade update and delete has to be translated into DDL

class Parent

@OneToOne(mappedBy = "parent", cascade = CascadeType.ALL)
public Child getChild()

class Child

@OneToOne(fetch = FetchType.LAZY)
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name="parent_id")
public Parent getParent()

I've got point 1, 3, 4 fully working and Point 5 partially working, still need to solve how to translate the update part indo DDL.

Point 2 is the big issue here, with my current solution the parent does not load the child lazily. The child however does load the parent lazily, but inverting the annotations would mess upp the cascading (points 3, 4 and 5).

I'm very confused right now, hoping I've missed something obvious, so any help would be greatly appreciated.

EDIT: Code requested by Adeel Ansari

'fetch=FetchType.LAZY' has been added to class Parent, otherwise the same as above.

IParentDAO parentDAO = DAOFactory.getFactory().getParentDAO();

parentDAO.beginTransaction();
//findByPrimaryKey uses 'org.hibernate.Session.get(Class clazz, Serializable id)'
parentDAO.findByPrimaryKey(1l);
parentDAO.commitTransaction();

The resulting hibernate queries, one fetching Parent and one fetching Child:

Hibernate: select parent0_.id as id0_0_ from parents parent0_ where parent0_.id=?
Hibernate: select child0_.id as id1_0_, child0_.parent_id as parent2_1_0_ from childs child0_ where child0_.parent_id=?

Here's the code for findByPrimaryKey:

public class HibernateParentDAO extends HibernateDAO<Parent, Long> implements IParentDAO {

    public HibernateParentDAO() {
        super(Parent.class);
    }
}

public abstract class HibernateDAO<T, ID extends Serializable> implements IGenericDAO<T, ID> {
    private Class<T> persistentClass;

    public HibernateDAO(Class<T> c) {
        persistentClass = c;
    }

    @SuppressWarnings("unchecked")
    public T findByPrimaryKey(ID id) {
        return (T) HibernateUtil.getSession().get(persistentClass, id);
    }
}

Answer

iliaden picture iliaden · Jun 9, 2011

I've been having a similar issue. There are a few different solutions, but all of them are workarounds.

The short answer is: Hibernate does NOT support lazy one-to-one relationships.

The long answer (workaround) is:

  1. Declare the relationship to be one-to-one on one side (child), and one-to-many on the other side (parent). Thus a parent.getchild() returns a set, yet it will be able to use lazy loading.

  2. You can try to have the parent and the children to share the primary key, but this would require you to alter the schema.

  3. You can try to configure a view in your database reflecting this one-to-one relationship.