So, the Credentials object comes back, and it has an association with a Member. The Member is associated in a Lazy manner, so the Member is only loaded when the Credentials object needs it.
So, in this query, a Credentials object comes back initialized, but Hibernate does you the favor of only bringing back proxies for the many possible Member instances. The proxies are placeholders that will only ever be initialized if you explicitly ask for them through the getter of the Credentials object.
Now, the problem with lazy loading is that those getters on the Credentials object will only work if they are called within the confines of the transaction that loaded the the original Credential. If the transaction is committed without a member getter ever being called on the Credential, the transactional context is closed, and your Credential object has no way of using Hibernate to get the associated Member. The Hibernate Session wipes its hands clean of the associated credentials object once the transaction is comitted - the Credential becomes a detached instance once the transaction is committed, as opposed to a persistent instance that is managed by the Hibernate Session.
This method call though:
//log.info(" member: "+ member);
Does force Hibernate to replace the proxy with a real object. The transaction is live, so the data comes back. The POJO on the JVM is now real, and that's why this little gem of code makes everything work - the PROXY is replaced by a real object, DURING a transaction, and the member POJO lives on in the JVM after the transaction is committed.
I have a little tutorial on How Hibernate Works that discusses this.
How Hibernate Works Of course, this doesn't solve the problem...
So, what you can do is mark the Credential to have a FetchType of EAGER, as opposed to LAZY. This way, all the Member objects will be loaded when the credential is loaded.
Another option is to extend the life of the transaction. Many 'simple' web applications use a single-transaction-per-cycle
pattern (anti-pattern?) so the whole request-response cycle is done within a single transaction, which ends any LazyLoading problems. I think you can figure some drawbacks to that of course.
Another option might be to do a full load of the Credential object before doing the logging. Of course, that would probably cause more potential problems to log.
>>P.P.S. Is the transaction really necessary when doing a query?
I've been on a couple of blog sites (Googled them but couldn't find them), but I've read one of the writers of Hibernate (Bauer or King, can't remember) get very 'testy' when asked about this. Something about asking this question to their students after a week long class, and then throwing erasers at everyone that gets it wrong. Yes, a transaction is needed. Certainly, a Hibernate Session is needed to load data from the database, and an open, working, queryable session goes hand in hand with an open transaction.
And even more to the point, with one to many relationships, it may have be the same session that originally loaded the one side of the relationship. With a new session, the one side of the relationship will need to be reattached to the Hibernate Session, lest it be detached and trigger another LazyLoadingException.
By the way, JQuery in Action was very well done.
-Cameron McKenzie
[ April 27, 2008: Message edited by: Cameron Wallace McKenzie ]
[ April 27, 2008: Message edited by: Cameron Wallace McKenzie ]