-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 24 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Hibernate and Tapestry
PostPosted: Thu Feb 24, 2005 2:44 pm 
Newbie

Joined: Thu Oct 21, 2004 3:03 pm
Posts: 13
I'm using Hibernate 2.1 with Tapestry 3.0.1. I've had reasonably good success if I avoid lazy collection initialization, but I have struggled to find a reliable method of dealing with lazy initialization.

I started with the recommended ThreadLocal session implementation (ie - the HibernateUtil class), which worked in some (simple) cases. I repeatedly found recommendations to implement Spring's OpenSessionInViewFilter, so I have spent the last few days ramping up on Spring. The lazy issues I had are now improved, but I'm still running into certain cases where it crops up. Since I'm using Tapestry, I will try to illustrate a simple scenario (I can give more details if needed):

Load an Incident, which has a lazy one-to-many with IncidentLine.
setIncident(incident) in a view page.
Option is selected to edit the incident.
EditIncident page "editPage" is instantiated.
editPage.setIncident(incident)
cycle.activate(editPage) to activate the EditIncident page.
From pageBeginRender() of my EditIncident page:
Incident incident = getIncident();
incident.getIncidentLineList() fails

I get Failed to lazily initialize a collection - no session or session was closed. I've confirmed in my logs that a session is open (managed by Spring), but I think my problem is that my Incident instance has not been reassociated with the open session.

If I walk through the above steps in a debugger, everything works fine since my debugger initially touched and forced the loading of the IncidentLines.

The sequence above is typical for Tapestry-based applications, and I really want to use Hibernate, but I am stuck for a general-purpose solution. I can provide more details of my Hibernate and Spring configuration if that would be helpful.

Here are a few log entries where the exception is thrown:
Code:
DEBUG 2005-02-24 11:11:37,258 [SocketListener0-0] net.sf.hibernate.transaction.JDBCTransaction - commit
DEBUG 2005-02-24 11:11:37,258 [SocketListener0-0] net.sf.hibernate.impl.SessionImpl - transaction completion
DEBUG 2005-02-24 11:11:37,258 [SocketListener0-0] net.sf.hibernate.transaction.JDBCTransaction - re-enabling autocommit
DEBUG 2005-02-24 11:11:37,258 [SocketListener0-0] org.springframework.orm.hibernate.HibernateTransactionManager - Triggering afterCompletion synchronization
DEBUG 2005-02-24 11:11:37,258 [SocketListener0-0] org.springframework.transaction.support.TransactionSynchronizationManager - Clearing transaction synchronization
DEBUG 2005-02-24 11:11:37,258 [SocketListener0-0] org.springframework.transaction.support.TransactionSynchronizationManager - Removed value [org.springframework.jdbc.datasource.ConnectionHolder@1071537] for key [com.mchange.v2.c3p0.ComboPooledDataSource@7103af] from thread [SocketListener0-0]
DEBUG 2005-02-24 11:11:37,258 [SocketListener0-0] org.springframework.jdbc.datasource.DataSourceUtils - Resetting read-only flag of connection [com.mchange.v2.c3p0.impl.NewProxyConnection@6a086a]
DEBUG 2005-02-24 11:11:37,258 [SocketListener0-0] org.springframework.orm.hibernate.HibernateTransactionManager - Not closing pre-bound Hibernate session [net.sf.hibernate.impl.SessionImpl@24c3aa] after transaction
ERROR 2005-02-24 11:11:37,258 [SocketListener0-0] net.sf.hibernate.LazyInitializationException - Failed to lazily initialize a collection - no session or session was closed


Can anyone see anything unusual about these messages?

I would tremendously appreciate any pointers.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 24, 2005 7:01 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 7:19 pm
Posts: 2364
Location: Brisbane, Australia
I have been building a medium sized application 200+ tables, 300+ pages using Tapestry and Hibernate. I use a different architecure, eg, SLSB and command pattern(s). I feel comfortable with loading what is appropriate for rendering the page using Hibernate objects that are transient. Obviously, I am carefull to make sure I use eager fetching for lazy properties.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 25, 2005 11:43 am 
Newbie

Joined: Thu Oct 21, 2004 3:03 pm
Posts: 13
I'm beginning to move that direction as well, but I'm also now wondering whether lazy initialization is warranted at all (or very often at least). I am new to Hibernate, and I had hoped initially that I could use lazy initialization as a matter of course, but now I'm thinking I should use it in only in rare cases.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 25, 2005 11:56 am 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
Lazy initialisation should be the majority of cases definitely! Or do you want to load your whole DB all the time? There are two easy routes: Either enable lazy loading in the View (OpenSessionInView) or prefetch your data (fetch keyword in HQL, etc.)


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 25, 2005 12:21 pm 
Newbie

Joined: Thu Oct 21, 2004 3:03 pm
Posts: 13
Lazy initialization is my preference (as I mentioned), but I've found it unreliable. I may very well be doing something wrong, but I have by no means found it easy.

If I use "fetch", doesn't that just override lazy=true?

As I described earlier, I am in fact using Spring's implementation of OSIV. It helped in many cases (80%), but in more complex situations it has not been beneficial. In fact, many of the Spring experts recommend moving away from the OSIV filter, and all of them I've found have stated it is not the answer in all cases.

If you are familiar with Tapestry, can you look over the sequence of events I described earlier and tell me what I'm doing wrong? As I mentioned, if I'm debugging in an IDE, everything is fine (since the lazy collection was forced to load for the debugger), and everything is also fine if I set lazy=false.

While I'm new to Hibernate, I have been using it for the last five months or so and it has worked pretty well with small, simple projects. For more complex applications, it has been a hindrance over plain JDBC. Regardless, I like Hibernate in theory and would really like to use it if possible. I also understand that improvements in session and transaction-management areas (especially relating to lazy inits) are coming in 3.0, so I will look forward to that.

Anyway, I'm sure I'm doing something terribly wrong in my earlier example, so anything you can suggest would be very appreciated.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 25, 2005 10:43 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 7:19 pm
Posts: 2364
Location: Brisbane, Australia
Mike is correct. There are your options and yes you should be using lazy initialisation for the majority of cases.

I don't use the Filter approach for anything beyond simple applications. HQL is powerfull and 'left join fetch' is your friend. Sure you endup writing longer queries but with the benefit of less requests being sent to the database.

That just my preference.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 25, 2005 11:15 pm 
Newbie

Joined: Fri Sep 26, 2003 4:29 pm
Posts: 16
My preference also. Mark everything as lazy and proxied and explicitly load the data I need.

In your initial message it looks like you are loading your incident in one request and then passing it to another edit page in another request, which is where you get the failure. So, you are using detatched objects between requests (and hence sessions) but you don't mention reattaching the incident object when you try and reuse it. Maybe that's causing the problem

david wrote:
Mike is correct. There are your options and yes you should be using lazy initialisation for the majority of cases.

I don't use the Filter approach for anything beyond simple applications. HQL is powerfull and 'left join fetch' is your friend. Sure you endup writing longer queries but with the benefit of less requests being sent to the database.

That just my preference.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Feb 26, 2005 12:55 am 
Regular
Regular

Joined: Mon Oct 20, 2003 3:14 am
Posts: 53
Location: Sterling, VA, USA
If you never declare anyting to be Lazy, doing a Session.find() for a single Cat makes Hibernate pull the whole blessed family tree...

_________________
"A statistician is a mathmetician, broken down by age and sex".


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 28, 2005 6:32 pm 
Newbie

Joined: Thu Oct 21, 2004 3:03 pm
Posts: 13
Thanks for your reply David. Can you clarify however why/when you prefer to use fetch? If I'm trying to keep my application layers as distinct as possible, my service layer won't know whether the business or presentation layers require a fetch to initialize lazy collections or not, right? Many times even my presentation layer won't know initially whether or not a related collection will be needed, since it often depends upon how a user moves through an application.

The Hibernate reference says this:

In an application with a separate business tier, the business logic must "prepare" all collections that will be needed by the web tier before returning. This means that the business tier should load all the data and return all the data already initialized to the presentation/web tier that is required for a particular use case. Usually, the application calls Hibernate.initialize() for each collection that will be needed in the web tier (this call must occur before the session is closed) or retrieves the collection eagerly using a Hibernate query with a FETCH clause.
...

This best describes presentation layers which implement a push model, but for frameworks such as Tapestry, a pull model is more natural. I don't mind longer queries, but I'm not sure in practice how to know whether to fetch or not. If I specify fetch in every case (for a particular collection), then isn't this equivalent to lazy=false?

Thanks again for your help.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 28, 2005 8:51 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 7:19 pm
Posts: 2364
Location: Brisbane, Australia
The page rendering process knows what state it is in and thus the data required to render it, eg, a state diagram for the mode. For example, You present a page with a master child relationship. State one just presents a list of parent classes so the query to the business layer knows its on page X in state 1 so only the parent list is loaded (where the data shown might require some extra fetching say for any lazy many-to-ones). The user selects a parent to the backend is called with page X and state 2 with parent record subject. The approrpiate loading occurs to render the list of parents and now the selected list of child records (Hibernate.initialise()) for the subject parent. The page is rendered. Lasy loading for the collection in this case is important since all the children of the parents are not loaded for this page. This is a simple and to a degree contrived example but it illustrates my basic approach.

If a use case allows the prefetch using the fetch HQL key word then I would use it in preference to HIbernate.initialise() to save a hit to the database through to cost of the extra hit may not be a real issue.

Obviously if your use case for a particular object relation always requires it to be loaded then yes it should be eagerly loaded. Often I classify lookup objects in the category.


Top
 Profile  
 
 Post subject: Tapestry and Hibernate
PostPosted: Tue Nov 08, 2005 8:07 am 
Newbie

Joined: Tue Nov 08, 2005 7:48 am
Posts: 5
I am trying to use lazy loading in Tapestry and cannot get it to work.

I have in the meantime made my object model use join="fetch" to get the sub-objects data (which affectively disables lazy loading). But this means our application loads large amounts of data when it is not needed.

This is all ok when dealing with one instance of an object as the object graph is not too bad for one object - the problem arises when we do searches.

When doing a search the system might be loading a few thousand instances of that large object graph. Which causes major performance issues for us.

I have tried managing the session across requests using the Spring "OpenSessionInView" Filter but that does not help as Tapestry pages keep around object references that were loaded during previous requests.

If some part of the object graph is lazily loaded, it isn't always possible to reattach it to the current session, because there is not enough information in the proxy, this is the case for example with a polymorphic class.

Anybody nailed this one down yet?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 08, 2005 8:23 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
"OpenSessionInViewFilter" must work with any web frameworks without problems if it does not start thread (I hope Tapestry doe's not start threads). It must be something wrong in the way you are using Tapestry.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Nov 08, 2005 3:33 pm 
Newbie

Joined: Tue Nov 08, 2005 7:48 am
Posts: 5
I have put an entry on the tapestry user list and found that this is a common problem with no clear solution at the moment. Some people talk of reattaching hibernate objects in pageBeginRender but when I tried some of these techniques they failed or they are giving it more thought.

http://thread.gmane.org/gmane.comp.java ... user/15398
or
http://article.gmane.org/gmane.comp.jav ... user/28116

I wish someone had a clear and clean solution - something using Spring would be good.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 09, 2005 12:47 am 
Regular
Regular

Joined: Wed Aug 25, 2004 7:40 pm
Posts: 65
david wrote:
The page rendering process knows what state it is in and thus the data required to render it, eg, a state diagram for the mode. For example, You present a page with a master child relationship. State one just presents a list of parent classes so the query to the business layer knows its on page X in state 1 so only the parent list is loaded (where the data shown might require some extra fetching say for any lazy many-to-ones). The user selects a parent to the backend is called with page X and state 2 with parent record subject. The approrpiate loading occurs to render the list of parents and now the selected list of child records (Hibernate.initialise()) for the subject parent. The page is rendered. Lasy loading for the collection in this case is important since all the children of the parents are not loaded for this page. This is a simple and to a degree contrived example but it illustrates my basic approach.

If a use case allows the prefetch using the fetch HQL key word then I would use it in preference to HIbernate.initialise() to save a hit to the database through to cost of the extra hit may not be a real issue.

Obviously if your use case for a particular object relation always requires it to be loaded then yes it should be eagerly loaded. Often I classify lookup objects in the category.


The master-child relationship David describes here is one of most common scenario. In regarding of performance, one article (on the java.net) says that instead of retrieving the object in the master list, it is better only retrieving the needed fields. If it is true, I need to rework on my code.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 09, 2005 3:42 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
Doe's Tapestry store persistent objects in HTTPSession ?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 24 posts ]  Go to page 1, 2  Next

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.