-->
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.  [ 3 posts ] 
Author Message
 Post subject: Lazy Property Loading On Demand
PostPosted: Mon Sep 13, 2004 5:46 pm 
Newbie

Joined: Mon Sep 13, 2004 5:25 pm
Posts: 2
Location: New York, NY
Hibernate version: 3.0
Name and version of the database you are using: Postgres 7.4


We are trying to develop an application using Hibernate that uses lazy loading but does not expose this fact to any business objects. What we would like to do is have an object automatically load its uninitialized attributes on demand, without throwing a LazyInitializationException even though the session is closed. We are trying to keep a strict separation between the business layer and the data layer so as not to expose any particular persistence mechanism.

Assume we've got two persistent classes User and Permissions where User has a one-to-many relationship with Permissions.

When a business object invokes UserManager.loadUserByName() the UserManager will take the following steps:
create a session from the SessionFactory.
Load a User object via the session.
close the session.
return the User object.

The collection of permissions has not been referenced so the collection has not been initialized. I want to make it so that if the business object now tries to access the permissions it will not get the lazy initialization exception.

There are a few ways to solve this problem but the normal hibernate scenarios don't work for us.
Normal Hibernate Solution 1: Leave the Session open. - we can't do this as we don't know what the business layer is going to do with this object, how long it will take or if it will let us know when it is done. We can't risk having a connection leak.

Normal Hibernate Solution 2: Initialize the permissions collection before we return it. - we can't do this as it is an expensive operation and the business objects won't always need it.

Our Solution: Have the User class intelligently return the collection initializing it when neccessary. Use a variation on the ThreadLocalSession pattern and instead of closing the Session in UserManager, disconnect it. This way in the User object we can have the following method:


Code:

public class User
{

...

  public List getPermissions(){
    if( !Hibernate.isInitialized( permissions ) )
        try
        {
           ThreadLocalSession.reconnect();
           Hibernate.initialize( permissions );
        }
        finally
        {
           ThreadLocalSession.disconnect();
        }
    }

    return permissions;
  }
}


Will this method cause problems with Hibernate persistence? I assume Hibernate will be using the getPermissions() method when it wants to persist the User object. This seems like everytime the User class is persisted the relationship would get initialized even if it hadn't needed loading or persisting. This could possibly be prevented by having the actual Hibernate persisted property being _permissions forcing hibernate to use private get/set_Permissions while the business layer is using the public getPermissions method.

Is there a simpler Solution that I am missing?

Also, this is just a single example. We would use this same model for almost all relationships in our persistent objects.

thanks,

Daniel[/url]


Top
 Profile  
 
 Post subject: Lazy Initializer Method
PostPosted: Tue Sep 14, 2004 5:52 pm 
Newbie

Joined: Mon Sep 13, 2004 5:25 pm
Posts: 2
Location: New York, NY
It turns out the ThreadLocalSession wouldn't work in our setup anyway so we ended up creating our own Lazy Initializer class. This class should allow the lazy initialization of Hibernate proxies. This method is called by the various "get" methods in our persistent code. Just be careful not to put the call to this method in the same method that Hibernate is going to call to persist your object. Otherwise all your lazy properties will be initialized whenever you save. The stack overflow protection will prevent any egregious errors but that won't stop sub-optimal code.

If this violates any major Hibernate concepts, please let me know.

Daniel

Code:
public class LazyInitializer
{

   // lock set to prevent stack overflows
  private static Set callerSet = new HashSet();

  public static Object initLazyProxy(Object caller, Object lazyProxy)
  {
    synchronized (caller)
    {
      try
      {
        if (!Hibernate.isInitialized(lazyProxy) && !callerSet.contains(caller))
        {
          Session s = null;
          try
          {
            // if the session is open we don't want to force them to
            // open a new one. 
            Hibernate.initialize( lazyProxy );
          }catch( HibernateException e ){
            // this is probably due to the fact that the session is closed.
            // mark that we are trying to load
            callerSet.add(caller);

            // re-associate with a new session.
            s = _sessionFactory.openSession();
            s.lock(caller, LockMode.NONE);

            // force the initialization
            Hibernate.initialize( lazyProxy );
          }
          finally
          {
            callerSet.remove(caller);
            if (s != null)
            {
              s.close();
            }
          }
        }
      }
      catch (HibernateException e)
      {
        throw new RuntimeException(e);
      }
    }
    return lazyProxy;
  }
}


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 27, 2004 5:08 pm 
Beginner
Beginner

Joined: Tue Jan 27, 2004 2:14 pm
Posts: 40
Location: Atlanta, GA, USA
I was wondering if you could post one of your domain objects so I can see how you implemented this. I am trying to do something similar to this and was wondering if you could share more of what you have discovered.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

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.