views:

491

answers:

4

I have a rather large project involving spring and hibernate. Right now, I'm backing certain objects out of hibernate and into memory, and I've hit a sort of snag. I have the following setup.

Class A contains a number of primitives and a class B. B contains primitives and a class C, which was previously lazy-loaded.

Now I have this

Service call 1:
1.) create object of class A
2.) get object of class B
3.) set B in A
4.) add A to memory

Service call 2:
1.) get A from memory
2.) get B from A
3.) get C from B
4.) operate on C

Because C is lazy loaded, it relied on a hibernate session existing to lazily load itself from B with hibernate, at least I believe this to be so. Now, however, I need to lazy load without modifying the DAO to return an ID, and there exists no current hibernate session to hijack into with OpenSessionInView. What's the best way to go about solving this problem, given the limitations? The only solutions I've found rely on unsuitable code change or an existing session, so I think that I could perhaps manually open a hibernate session. How would I go about doing this? Alternatively, is there a better solution to this problem?

+2  A: 

If you can get a reference to your configured SessionFactory, you should be able to just call openSession() on it.

Brian Yarger
I'm injecting the sessionFactory, so I'll try this.
Stefan Kendall
+1  A: 

As a best practice, you'll want to use a session factory. Here is the one Netbeans generates.

public class HibernateUtil {

    private static final SessionFactory sessionFactory;
    private static final Configuration configuration = new Configuration().configure();

    static {
        try {
            // Create the SessionFactory from standard (hibernate.cfg.xml) 
            // config file.
            sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            // Log the exception. 
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

Once you have this, you can use this code for a transaction

Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
//Do something
session.getTransaction().commit();

Note that opening a transaction will open a session. I believe under pure Hibernate (unlike JPA) you need a transaction to do anything, even reads.

At the end of the program you want to make sure you do this

HibernateUtil.getSessionFactory().close();

For a more sophisticated solution, you may want to look into automatic session/transaction management with Spring or EJB. Which will handle the session behind the scenes once configured properly.

EDIT:
Just re-read your question and your point about IDs. I believe the sessionfactory approach will work for your purposes, unless you are doing a multiple threaded application. This is because, by default, Hibernate sessions and the ORM objects linked to that session are associated to one thread only. Let me know if I am wrong about this.

James McMahon
A: 

Are you using HibernateTemplate and HibernateDaoSupport to implement your DAOs? If so, this is why your objects are disconnected. But, you should be able to use the OpenSessionInViewInterceptor in that case. Have you done anything to verify that you won't be able to use the interceptor?

Also, if you choose to open a new Session, the object in memory will not be associated with the new Session. You'll need to reattach the object to the session in order for the lazy loading to work.

Paul Morie
+1  A: 

If you know your B objects might have their C's referenced, you should be retrieving the B's in such a way as to pre-fetch the C's. For instance the HQL

from B as b where b.id = :ID

becomes

from B as b left join fetch b.c where b.id = :ID
Jherico