nordborg wrote:
You can try to make the collection lazy="extra" (hbm style, don't know it's counterpart with annotations). According to the docs this is a feature "where most operations do not initialize the collection". I have no idea if it will help in your case but it is wort a try.
Thanks, mate! It actually works! :-)
If I wasn't too lazy to read the Jave Persistence with Hibernate completely, I would have found it saying:
Java Persistence with Hibernate, on page 567 wrote:
...The collection wrapper is now smarter than before. The collection is no longer initialized if you call size(), contains(), or isEmpty()—the database is queried to retrieve the necessary information. If it’s a Map or a List, the operations containsKey() and get() also query the database directly...
The only problem with that book is it being sooo comprehensive... It's not the easiest literature on the subject, but it's great once you read it.
I just had to change the code above by adding a
@LazyCollection(LazyCollectionOption.EXTRA) at the biographyMap getter:
Code:
@CollectionOfElements
@LazyCollection(LazyCollectionOption.EXTRA)
@JoinTable(name = "PERSON_BIOGRAPHY", joinColumns = @JoinColumn(name = "PERSON_ID"))
@MapKey(columns = @Column(name = "LOCALE", length = 8))
@Column(name = "BIOGRAPHY")
public Map<Locale, String> getBiographyMap() {
return biographyMap;
}
Executing the following piece of code:
Code:
...
List<Person> persons = em.createQuery("select p from Person p order by p.name asc").getResultList();
System.out.println(persons.size() + " person(s) found:");
Person loadedPerson = persons.get(0);
System.out.println("Fetching biography for " + loadedPerson.getName());
System.out.println("Loaded biography: " + loadedPerson.getBiographyMap().get(new Locale("en")));
System.out.println("There are "+loadedPerson.getBiographyMap().size()+" translations");
...gets the following result:
Code:
Hibernate: select person0_.id as id2_, person0_.name as name2_, person0_.version as version2_ from Person person0_ order by person0_.name asc
41 person(s) found:
Fetching biography for John Doe
Hibernate: select BIOGRAPHY from PERSON_BIOGRAPHY where PERSON_ID =? and LOCALE =?
Loaded biography: English biography...
Hibernate: select count(BIOGRAPHY) from PERSON_BIOGRAPHY where PERSON_ID =?
There are 3 translations
Obviously, the Hibernate first loads the Person object, then loads just a
single row when accessing a map by a specific key. Also, calling a map.size() just queries the database to count the rows.
Unfortunately, map.keySet() loads the entire map together with the mapped objects, so querying a map keys must be done by writing a direct SQL:
Code:
Query q = getSession(em).createSQLQuery(
"select LOCALE from PERSON_BIOGRAPHY where PERSON_ID=:id").addScalar("LOCALE", Hibernate.LOCALE);
q.setParameter("id", personId);
List<Locale> list = q.list();
System.out.println("Available locales: " + list);
Thanks for the help!