Hibernate, best method of fetching one-to-many
Background
I recently started a new Java EE 6 object, using JBoss and Hibernate. From earlier projects, I have experience with Glassfish using Eclipselink as JPA provider.
In my earlier project, I mapped up all relations as Lists, and when I knew I was going to need large batches of data from a relationship, I would fetch the data needed. If I forgot to fetch something, it could be lazy loaded later from the view/controller layer. Using Hibernate, I discovered that things works very differently than other providers regarding lazy loading and fetches (not allowing lazy loading outside an EJB, not allowing more than a single fetch/eager load).
Question
What is the de-facto standard of handling fetching with Hibernate? I see a few possibilities:
Map one-to-many to List as earlier, but using @IndexColumn. Use fetch through criteria api, causing joins.
Pros: design looks decent. Cons: need to change table structure, joins have very bad performance with a deep structure.Map one-to-many to Set. Allows multiple fetches.
Pros: no need for @IndexColumn. Cons: No sorting, would often need to convert it to a List and back to use many JSF 2 components that wants a list.Map one-to-many to List and use hibernate specific @Fetch annotation on entity classes, mostly with FetchMode.SUBSELECT, together with lazy loading. EJB methods would not use fetches, but simply make a simple select, then manually read from the selected object and "lazy load" relations that we want to fetch.
Pros: very good performance due to subselects. No need for @IndexColumn. Cons: very weird-looking looking EJB methods, due to the need to manually load relationsships (see below for example).
Example of #3
public List<User开发者_如何学JAVA> findAllUsers(){
CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> from = cq.from(User.class);
List<User> users = em.createQuery(cq).getResultList();
if(users.isEmpty())
return users;
users.get(0).getRoleList().size();
users.get(0).getUserHasCompanyList().size();
users.get(0).getUserInUnitList().size();
return users;
}
With such a common scenario as wanting a few entities loaded with relationships to use in the controller/view layer, is there really no better alternative?
I would recommend using the sets for the following reasons:
1) you DO NOT touch the schema. it's always best practice to leave the schema untouched
2) you can sort the sets after fetching them from the db. For example:
List<MyType> list = query.list();
Collections.sort( list, myComparator );
3) sets can be both lazily and eagerly fetched with any type of mapping (xml or annotations)
精彩评论