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.  [ 1 post ] 
Author Message
 Post subject: Dynamically load a child collection after session close.
PostPosted: Fri Jan 22, 2010 8:42 pm 
Newbie

Joined: Fri Jan 22, 2010 8:10 pm
Posts: 1
Hello!

I'm working on an application which are supposed to be a database back end for a web and mobile application.

I have three main classes which are saved to the database; User, Session and Location.

A User can have an arbitrary number of sessions, and each session can have an arbitrary number of locations.
Beyond this, none of them are connected in any way.

So a User can have many Sessions, and each Session can have many Locations.

I have created the mappings and all works well. I can add sessions to a user and locations to the session, and they all get saved to the database.

No, the problem is that I don't want to fetch everything associated with a User when I get a User from the database. For example, a Session can have thousands of locations, which I only want to fetch when I actually need them, and that's why I use the lazy initialization method.

Say I have fetched a user, and closed the session associated with the transaction, effectively blocking any attempts of fetching the Sessions belonging to the User. How can I fetch these sessions on demand?

Here is my fetch user function:
Code:
   public User getUser( Long id ) {
      if ( id == null ) {
         throw new IllegalArgumentException("userId is null");
      }
      Session session = HibernateUtil.getSessionFactory().openSession();
      Transaction transaction = null;
      User u = null;
      try {
         transaction = session.beginTransaction();
         u = (User) session.get(User.class, id);
         transaction.commit();
      }  catch( RuntimeException re ) {
         if ( transaction != null && transaction.isActive() ) {
            try {
               transaction.rollback();
            } catch( HibernateException he ) {
               logger.debug("Could not rollback transaction.");
            }
         }
         throw re;
      } finally {
         session.close();
      }
      
      return u;
   }


I have come up with a few solutions, but I don't like either of them.

1. create another function which uses Hibernate.initialize( u.getSessions() ); to get the session set before returning the User
2. send the user object to a function (initializeSessions) which fetches the User again with the function described i 1, and use the setSessions() on the object passed to the function with the getSessions() from the newly fetched user - this removes the need of the caller having to change it's user pointer

What I want is 2. but without the need of fetching the user, but only fetch the Sessions and add them to the already existing User object.
I tried to open a new hibernate session and transaction and call Hibernate.initialize( u.getSessions() ); but that gave me the "collection is not associated with any session" exception, see below:

Code:
   public void initializeSessions( User u ) {
      
      org.hibernate.Session session = HibernateUtil.getSessionFactory().openSession();
      Transaction tx = null;
      try {
         tx = session.beginTransaction();
         
         Hibernate.initialize(u.getSessions());
         
                  
         tx.commit();
      } catch( RuntimeException e ) {
         if ( tx != null && tx.isActive() ) {
            try {
               tx.rollback();
            } catch( HibernateException he ) {
               logger.error("Could not rollback transaction.");
            }
         }
         throw e;
      } finally {
         session.close();
      }
   }


Is there any good way of doing this? I would like to have this on the Session to Locations as well with a function called initializeLocations(Sesssion s);




Here's the hbm.xml files for the three classes User, Session and Location:

Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
   <class name="no.sygard.tracking.manager.User" table="users">
      <meta attribute="class-description">
         This class contains the user details.
      </meta>
      <id name="userId" type="long" column="userId">
         <generator class="native"/>
      </id>
      <property name="username" type="string" column="username" not-null="true" unique="true" />
      <property name="password" type="string" column="password" not-null="true" />
      <property name="email" type="string" column="email" not-null="true" unique="true" />
      <property name="created" type="timestamp" column="created" not-null="true" />
      <property name="imageUrl" type="string" column="imageUrl" not-null="true" />
      <property name="apiKey" type="string" column="apiKey" not-null="true" unique="true" />
      <property name="lastLogin" type="timestamp" column="lastLogin" not-null="true" />
      <property name="lastLoginIp" type="string" column="lastLoginIp" not-null="true" />
      <property name="lastApiLogin" type="timestamp" column="lastApiLogin" not-null="true" />
      <property name="firstname" type="string" column="firstname" not-null="true" />
      <property name="lastname" type="string" column="lastname" not-null="true" />
      <set name="sessions" table="user_session" cascade="all">
         <key column="userId" />
         <many-to-many column="sessionId" unique="true"
            class="no.sygard.tracking.manager.Session" />
      </set>
   </class>
</hibernate-mapping>


Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
   <class name="no.sygard.tracking.manager.Session" table="sessions">
      <meta attribute="class-description">
         This class contains the session details.
      </meta>
      <id name="sessionId" type="long" column="sessionId">
         <generator class="native"/>
      </id>
      <property name="name" type="string" column="name" not-null="true" />
      <property name="description" type="string" column="description" not-null="true" />
      <property name="created" type="timestamp" column="created" not-null="true" />
      <property name="active" type="boolean" column="active" not-null="true" />
      <set name="locations" table="session_location" cascade="all">
         <key column="sessionId" />
         <many-to-many column="locationId" unique="true"
            class="no.sygard.tracking.manager.Location" />
      </set>
   </class>
</hibernate-mapping>


Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
   <class name="no.sygard.tracking.manager.Location" table="locations">
      <meta attribute="class-description">
         This class contains the location details.
      </meta>
      <id name="locationId" type="long" column="locationId">
         <generator class="native"/>
      </id>
      <property name="latitude" type="double" column="latitude" not-null="true" />
      <property name="longitude" type="double" column="longitude" not-null="true" />
      <property name="speed" type="double" column="speed" not-null="true" />
      <property name="altitude" type="double" column="altitude" not-null="true" />
      <property name="accuracy" type="double" column="accuracy" not-null="true" />
      <property name="bearing" type="double" column="bearing" not-null="true" />
      <property name="provider" type="string" column="provider" not-null="true" />
      <property name="time" type="timestamp" column="time" not-null="true" />   
   </class>
</hibernate-mapping>


If anyone have any good solutions or just say that it cannot be done, I would really appreciate it !


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

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.