-->
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.  [ 18 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Reconnect Collection Proxy after session.close()
PostPosted: Wed Feb 11, 2004 6:39 am 
Beginner
Beginner

Joined: Wed Feb 11, 2004 6:08 am
Posts: 29
Location: Germany
Hello,

ist there a way to reconnect a collection proxy after the session has been closed in a previous request?

I have the following master/detail mapping with a lazy proxy "OrderItem":

Code:
   class Order {
     private String description;   
     private Set orderItems; ...
   }

    <class name="Order" table="ORDER">
            <set name="items" table="CDMEXPT0"  lazy="true">
                    <key>
                         <column name="CLID" />
                         <column name="ORDID" />
                     </key>
                      <one-to-many class="OrderItem"/>
             </set>
   <property name="description" column="DESC"/>
    </class>


In my scenario I have two UseCases:

UseCase A : Show Master Information, executed first
Code:
Session session = sf.open()
OrderItem order = select order from OrderItem as order where ...
order.getDescription();
session.close().


then, after the session.close() (and displaying the JSP) the user requests the order details. The order reference is the same as in UseCase A (e.g. stored in HttpSession), so the Order.orderItems holds a proxy.

UseCase B : Show Detail Information
Code:
Session session = sf.open();
order.getItems().iterator();   


order.getItems() throws an Exception "no session", because the previous session has been closed.

Does that mean that I cant use a collection proxy anymore once the session has been closed?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 11, 2004 6:50 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Woah, the fourth question about this in two days. Is there some new tutorial somewhere? Here is what I said earlier:

Keep the Session open for one request, close it when all business logic in that thread has been executed. This is the common pattern, see:

http://www.hibernate.org/168.html

Use a call Interceptor (this can even be a Servlet filter) to do this, the pattern is called "Open Session in view". No, this doesn't create a dependency between the Presentation and the Persistence layer, it's a function of the global System layer that manages resources.

The Session is also the first-level cache. Whenever you load()/get() or navigate an object, it gets added to that cache. You will end up with lots of stale data if you re-use the same Session for a long time. A single Session is a single Unit-of-Work, and usually has the same scope as a single database transaction.

Long and disconnected Sessions are definitely an advanced case and not for the beginner still struggling with the basic scopes.

This is the third question in two days about "can we just open a new Session" whenever we access a proxy. No, we won't do it and you shouldn't. Think about it: Your transaction semantics would be ad-hoc: When do we close the second new Session? After lazy loading a single proxy? This second Session of course also opens a new database transaction: Is the original object still there? What do we do if it has been deleted?

This opens a can of worms you (and we) can't control. Just take care you retrieve the right amount of data you need for a use case. Lazy loading accross tiers just doesn't work.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 11, 2004 7:38 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
christian wrote:
Long and disconnected Sessions are definitely an advanced case and not for the beginner still struggling with the basic scopes.

This is the third question in two days about "can we just open a new Session" whenever we access a proxy. No, we won't do it and you shouldn't. Think about it: Your transaction semantics would be ad-hoc: When do we close the second new Session? After lazy loading a single proxy? This second Session of course also opens a new database transaction: Is the original object still there? What do we do if it has been deleted?

This opens a can of worms you (and we) can't control. Just take care you retrieve the right amount of data you need for a use case. Lazy loading accross tiers just doesn't work.


It is possible to solve using ThreadLocal session per session factory by hibernate internaly, It can break transaction semantics, but not more than
"disconnected Sessions".


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 11, 2004 7:43 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Thats true, but with disconnected Sessions (or detached objects), application transaction semantics are _explicit_. If Hibernate would do it, it would implicitly, and quite transparently break your transaction semantics.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 11, 2004 8:08 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
It must not be very problematic to implement by user himself ("currentSession"). I am not sure about current hibernate architecture, but
I hope it is possible to implement custom SessinFactory:

1. Implement Session this way :


class MySession implements Session {
MySessionFactory factory;
MySession(MySessionFactory factory){
this.factory = factory;
}

Session getSession(){
//ThreadLocal
return factory.currentSession();

}
//all session methos implemented this way:

void save(Object o){
getSession().save(o);
}
..................................
}


2. implement custom SessionFactory (trivial wrapper with "currentSession()" implementation)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 11, 2004 8:52 am 
Beginner
Beginner

Joined: Wed Feb 11, 2004 6:08 am
Posts: 29
Location: Germany
thank you for your promt reply!

sorry, I should have made my design goals clear. I have read the pattern section, but I couln't find a solution for the following design requirement:

I want to encapsulate all DB-access code in a DAO layer, so that the client (web) app is not aware of the underlying Hinbernate layer. This means : no session.open/close in servlet, servlet filter etc. on top of the business object layer.
Clients must not have access to any underlying integration layer API (including Hibernate, JDBC, EJBs etc...) in order to avoid dependencies.

the client should be able to use persistent objects in the following way:

Code:
  try {
    // begin JTA transaction
    Order order = OrderFactory.findOrderForClient(28);
    for (Iterator iter = order.getOrderItems().iterator(); iter.hasNext()) {
       OrderItem item = (OrderItem) iter.next();
       ... do lots of things with order items
    } 
    ... do lots of things with other persistent objects (maybe using a single thread local hibernate session internally)
    ... use some EJBs

    // commit JTA transaction
  } catch (BusinessException e) { // JTA rollback}


Note: The client is not required to open/close any Hibernate session object.

My idea was the following DAO desing (which doesnt seem to work with lazy proxies):

DAO
Code:

class OrderDAO {
   public Order findForClient(int clientID) throws DAOException {
      try {
        Session session = DB.getSessionViaThreadLocalPattern();
        Order  o = select Order ... where client = clientID ...
        DB.releaseSessionAsSoonAsTransactionCommitts(session);
        return o;
     } catch (HibernateException e) {throw new DAOException()}
   }
   ...
  public load(Set itemsProxy) {
        Session session = DB.getSessionViaThreadLocalPattern();
        Hibernate.initialize(itemsProxy);   // throws "no session" exception
        DB.releaseSessionAsSoonAsTransactionCommitts(session);
  }
}


Despite using the above DAO I'd still like to be able to use Hibernates lazy proxies AFTER the session has been closed in a previous request:

Business Object
Code:
class Order {
   OrderDAO dao = new OrderDAO();
   private Set orderItems;

   Iterator getOrderItems() {
      if (!dao.isInitialized(this, orderItems))
         dao.load(orderItems);       // reconnect to Hibernate Session and replace proxy with real data. DOESNT WORK!
      return orderItems;
    }
}


If I cant replace proxies after the session has been closed in a previous reques I have to eagerly load all business object's associations at once in the first user request.

It looks like that I can use Hibernate with the above DAO design only for business objects that have composite semantics (i.e. detail associations are always loaded when the master is loaded).

Are there any designs which support the above design, completely encasulates Hibernate in a DAO layer and allow lazy loading ?!

Thanks

Dirk


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 11, 2004 8:58 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
THERE IS NO DEPENDENCY IF YOU USE A SERVLET FILTER OR INTERCEPTOR.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 11, 2004 9:08 am 
Beginner
Beginner

Joined: Wed Feb 11, 2004 6:08 am
Posts: 29
Location: Germany
Of course there is a dependeny if my client (web) app needs to be configured with a servlet filter that uses a Hibernate session!

If I omit the filter the web app wont work. This IS a dependency (although there is no import x.y.*; in my webapp)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 11, 2004 9:15 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
Look, we can argue about this for hours, but the fact is that:

- it is not a dependency in the BAD sense that many people now associate with the term, realise that there are different kinds of dependencies

-you have many more "dependencies" like this in your application without noticing it, as part of the runtime environment your application runs in

- it is part of the system layer that is accessed by all other layers, a traditional design

If you think that this is a real dependency, so is the dependency of your code on infrastructure artefacts like a Thread, a SecurityContext or even an Object.

There is no magic that we might one day discover that solves this "problem".

There is only one solution: An Interceptor knows when to send an Event to a Listener that will manage the Hibernate Session resource. There is no real dependency here, in the sense of a "code" dependency, the Observer and the Observable are decoupled. Of course you have to wire that Interceptor into your system. How else should it work?

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 11, 2004 10:16 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
100% agree with Christian, there is no negative in this "dependancy".
Any design must have technical motivation, this filter has very strong motivation.

"I want to encapsulate all DB-access code in a DAO layer, so that the client (web) app is not aware of the underlying Hinbernate layer."

And there is no conflicts with your design. "client (web) app" is not aware of the Filter, so it not aware of the hibernate code (or your wrapper API) in filter too.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 11, 2004 11:20 am 
Beginner
Beginner

Joined: Wed Feb 11, 2004 6:08 am
Posts: 29
Location: Germany
thank you for all your comments!

From that point of view you are right. The servlet filter approach is definitely a good approach for handling the session.open/close issue for a single request. It separates concernes and in that sense the client CODE is of course decoupled. But still, the client APP has a dependency; if I have e.g. 20 client applications using my DAO layer (developed at different locations in the world) it might become an organizational challenge to communicate all dependencies (especially if they change in future). But this might be a puristic point of view and is not my main issue...

The problem I have with Hibernates lazy object approach is that the proxies become useless as soon as the are detached from the initial session.

I dont see a reason why this has to be, because it basically means that I can navigate (lazy) associations only if the master object has been loaded within the scope of a Hibernate session. This is definitely a problem if I have a layered architecture like my DAOs above.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 11, 2004 11:33 am 
Regular
Regular

Joined: Tue Aug 26, 2003 3:09 pm
Posts: 58
dirkschmidt wrote:
The problem I have with Hibernates lazy object approach is that the proxies become useless as soon as the are detached from the initial session.


Just reattach the parent object to a new session using session.lock(obj, LockMode.NONE), then initialize the proxy.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 11, 2004 11:34 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
I explained the reason for this several postings ago, please read it again. Think about the transaction semantics of your application if Hibernate randomly opens new database transactions to retrieve proxies.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 11, 2004 12:55 pm 
Beginner
Beginner

Joined: Wed Feb 11, 2004 6:08 am
Posts: 29
Location: Germany
Quote:
Just reattach the parent object to a new session using session.lock(obj, LockMode.NONE), then initialize the proxy.

Thanks jfifield, that answered my question!


Quote:
Think about the transaction semantics of your application if Hibernate randomly opens new database transactions to retrieve proxies


I will


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 06, 2005 5:28 pm 
Regular
Regular

Joined: Thu Apr 14, 2005 2:15 pm
Posts: 66
Quote:
Think about the transaction semantics of your application if Hibernate randomly opens new database transactions to retrieve proxies.


Quote:
Just reattach the parent object to a new session using session.lock(obj, LockMode.NONE), then initialize the proxy.


So, this solution isn't a good pratice? I'm working in a swing application. I haven't any application server to use servlet filters.
If this isn't a good solution, what can I do?

Now, I have this code working:

Code:
   public ControladorTelaEdicaoTesoura(Tesoura tesoura) {
      super();
      visao.setTitle("Tesoura");
      visaoTesoura = (TelaEdicaoTesoura)visao;
      this.tesoura = tesoura;
      visaoTesoura.setDescricaoTesoura(tesoura.getDescricao());

      Session session = HibernateUtil.getSession();
      Transaction trans = session.beginTransaction();
      session.saveOrUpdate(tesoura);
      visaoTesoura.getPainelTabela().getTableModelPadrao().setLinhas(tesoura.getMateriais());
      visao.setVisible(true); //opens the JDialog
      trans.commit();
      session.close();      
   }   


Is it better if I load the tesoura object again to solve the problem of the deletion of it by other user?
ex: session.load( tesoura.getClass(), tesoura.getId() )


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 18 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.