reset password
Author Message
dguhath
Posts: 61
Posted 19:00 Feb 06, 2015 |

Hello Dr Sun,

I have been facing some issues in data loading. Specifically related to collections. Could you please tell me when exactly the framework fetches the inter dependent objects/collections. In some scenarios the data is available on accessing the get method but in some cases the list is empty and sometimes an exception is raised saying "failed to lazily initialize a collection". Could you please give me some pointers on what can we do to avoid encountering empty collections. 

cysun
Posts: 2935
Posted 20:58 Feb 06, 2015 |

Collections (i.e. @OneToMany and @ManyToMany) are by default loaded lazily, which means the data is not retrieved from the database until it's used. For example, suppose Account-Customer is many-to-one and the Customer class is like the following:

class Customer {
    Integer id;
    String name;
    Set<Account> accounts;
}

When you use customerDao.getCustomer() to load a Customer object, the accounts field is actually not initialized. It will remain uninitialized unless you call customer.getAccounts(), at which point the ORM will automatically sends anther query to the database and return the data.

Lazy loading is important for performance (otherwise you may load the whole database when you just want one object), so most of the time you should keep the default behavior. There are a couple of potential pitfalls though:

  • Lazy loading only works if you access the field using a getter, e.g. customer.getAccounts(). In other words, direct field access like customer.accounts won't work (or at least won't work without some additional AOP support).
  • Lazy loading only works if the object is managed by an entity manager. This is easy to understand - without an entity manager there's no automatically data retrieval.

The second point can get tricky when you use session attributes. The problem is that after a request is processed, the entity manager associated with that request is closed (you can think of it like closing a database connection after the request processing is done), and any objects saved in the session scope are no longer managed by an entity manager. Such objects are called detached objects, and you'll get an error if you try to do lazy loading on a detached object. There are two solutions for this: use FetchType.EAGER in @OneToMany or @ManyToMany to load the collection when the owning object is loaded, or re-attach the detached object to an entity manager with a merge() (and remember the re-attached object is the one returned by merge(), not the one passed to merge()).

Last edited by cysun at 21:01 Feb 06, 2015.
dguhath
Posts: 61
Posted 21:23 Feb 06, 2015 |

Thanks a lot Dr Sun. This is extremely useful information. I was missing out on the key fact of the entity manager getting detached. I was using the second approach as a work around but I was not sure whether it was a hack.

I have one more question for you. It's regarding data storing for similar collection related scenarios. What is the right way of transferring the data. Say for instance a new Account was created. Can the Customer object be used to save this information? What about any reverse link, in this case the Account having the Customer information. Should that be populated before transfering the data. Or should we always use the Account entity for saving an Account & a Customer for saving a Customer.

cysun
Posts: 2935
Posted 22:39 Feb 06, 2015 |

That's what cascade type is for (see the Hibernate lecture notes). For example, if you specify cascade type to be CascadeType.MERGE, when you save (i.e. merge) a Customer object, all the new/modified accounts of the customer will be saved too. And in this case, if Account has a Customer reference, you should do account.setCustomer(customer) before doing customerDao.saveCustomer(customer).

It doesn't matter whether you use AccountDao or CustomerDao (with cascade) to save accounts. I'll go with whichever that is more "natural" and/or convenient.

dguhath
Posts: 61
Posted 23:02 Feb 06, 2015 |

Thanks Dr.Sun. That helps.