• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Problem re-attaching transient objects

 
Vinnie Jenks
Ranch Hand
Posts: 207
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I've encountered a serious problem which pertains to this bug:

http://opensource2.atlassian.com/projects/hibernate/browse/HHH-511

Basically, I've got some objects that are queried and then disconnected from the session. When I try to alter the then transient objects and then re-attach them to a new session to save/update them...I get this exception:



I'm using the DAO architecture prescribed in Hibernate in Action in Chapter 8...where sessions are closed using a Servlet Filter. The objects most definitely have their original ID (primary key of record in DB) and are otherwise fine. The exception doesn't happen *every* time an update is performed, just occasionally.

I've covered every possible base I could find in Hibernate in Action such as;

The mappings define an unsaved-value attribute.

They are queried out w/ their ID value so Hibernate should "recognize" them and re-attach them.

I've tried calling evict() on the transient objects but it had no effect.

Hibernate in Action goes on, at-length about how good Hibernate is at re-attaching disconnected objects to new sessions but it would appear that there's a fairly serious bug?

Is there a solution to this? What is a good work-around that won't involve me re-writing a bunch of my app?

I'll provide more code, if necessary, but my post should be simple enough to understand, combined w/ the bug-report above. I open a session in a dao object...query some data....close the session in a Servlet Filter (one session per-request)...and then try to re-attach and save the object after the form is submitted.

Thanks!
 
Mark Spritzler
ranger
Sheriff
Posts: 17278
6
IntelliJ IDE Mac Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
We had that, and what it is is that you have two instance of the Data Object in your "List" and you call update on one, then later you get another Data Object for that same record and try to update that one too.

For example, we had a screen that had a list of say Three seperate records. IDs, 1-3. Then we returned a Collection of these records, which based on our App Logic created 4 Objects in the Collection, Objects for IDs 1-3, and another one for ID 1, so when we got the 4 records in the Collection, sent it to the server, then on the server iterated through the Collection calling update/save with each object, when it reached the 4th, which also had ID 1, then we get that exception.

Hope that is why.

Mark
 
Vinnie Jenks
Ranch Hand
Posts: 207
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No, I'm not sure we're talking about the same thing. I'm not trying to update anything in a List...I'm trying to update a single object that's been detached from my Session.

Really, the Hibernate bug report I posted the URL to explains it all, it's that exact problem...and I'm getting the exact same error in the same scenario as the users who commented on the bug.

I'm a little surprised, given the common nature of what I'm doing, that the bug has such low priority to the Hibernate team (unless, of course, they've already fixed it in the next release.)
 
Mark Spritzler
ranger
Sheriff
Posts: 17278
6
IntelliJ IDE Mac Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ah, so the deal is that the Session is still open and you are re-using the same Session. So the old Collection is still attached to that Session, and when you reattach the detached one, it goes, hey wait a second you already have that Collection attached, what are you trying to pull.

I have one rhetorical question. Why is the Session still open on the server side? Meaning you are keeping this session open until some unknown time that the client calls back and tries to reattach this Object. How are you storing the Session object, and will there be Thread issues with keeping this Sesison open?

OK, so that was many rhetorical questions.

Mark
 
Vinnie Jenks
Ranch Hand
Posts: 207
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Close, Mark, but alas - no cigar.


Ah, so the deal is that the Session is still open and you are re-using the same Session. So the old Collection is still attached to that Session, and when you reattach the detached one, it goes, hey wait a second you already have that Collection attached, what are you trying to pull.


You're right about everything here except the Session is *not* open after I retrieve the objects. I'm doing this in the following order:

1. Connect to session, retrieve a single object.
2. commit Transaction and close Session.
3. update object w/ new values.
4. Open session and do an update() or saveOrUpdate() on object.
5. Kablooie - it fails (not every time, it works more than it fails.)

Between steps 3 and 4 I've tried calling evict() manually but it did not help.

The fact that it fails may very well be a threading issue but I'm just following one of the suggested methods in Hibernate In Action where I use DAOs to open the session and Servlet Filter to close the session...so it's one session per-request. I would LOVE to hear a better way to do this that isn't insanely complicated or involves using the container to manage sessions/transactions...so please, if you know a better way, share!

-v
 
Vinnie Jenks
Ranch Hand
Posts: 207
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I found the problem and the work-around (but I'm not really satisfied w/ it...I know there must be a better way).

In doGet of my servlet I was getting a record via Hibernate by a parameter (querystring param i.e. ?id=10). Once I obtained that record, I assigned it to a global variable. Since I'm disconnecting from the session in doFilter the global object I had obtained became disconnected.

In doPost, once the form values were entered and it was submitted, I was grabbing that global object, changing the new values from the form, and then trying to open a new Hibernate Session and do saveOrUpdate() to that object.

Technically, this should work, shouldn't it? I realize there might be threading issues w/ the global object (I had forgotten I set it global when I initially created the app a few months ago.) However, shouldn't I *still* be able to re-connect a transient object and update it in a new session/transaction!?

I changed it to also do a new query in a new session in doPost, once the form was submitted, so everything happened in the same session context. This is bad because I have to make another round-trip to the database to obtain the object again...which I had already done in doGet.

Let me know if that makes any sense!
 
Mark Spritzler
ranger
Sheriff
Posts: 17278
6
IntelliJ IDE Mac Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
OK, other questions, the sstuff you say is "in" the doGet and doPost, isn't actually coded directly in those methods? You have them in POJOs that the doGet and doPost can call on instead, right?

But that is beside the point.

Yes, I would look for another solution, that global variable thing has me running for the doors.

We are using detached objects without any issues, not through a Servlet, but if you are using POJOs for this activity, then being a Servlet or not should make no difference.



Here is our service method from a POJO



Mark
 
Vinnie Jenks
Ranch Hand
Posts: 207
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well yeah, I guess I should have clarified. The servlet calls a proxy method which calls a data-access object (which is where Hibernate comes into play.) All of the business logic resides into the proxy/dao/model layer, each of which are in separate jars.

Here's an example of calling an object in this application using Hibernate...please feel free to point out where I'm going wrong or what I could be doing better!

Directory, the POJO I'm after



Directory.hbm.xml



servlet doGet (EditBusinessUnit.java)



proxy method call (DirectoryProxy.java)



DAO method call (DirectoryDAO.java)

NOTE: I've included the default constructor to show you how I'm opening the transaction.



And...as I mentioned...I'm using doFilter in my servlets (my servlets are also filters! ) to commit the transaction and close the session...

doFilter in servlet (EditBusinessUnit.java)



I like everything about this except for the hard-coded calls to Hibernate in the servlet (doFilter above). I'm sure there's a better way but I don't want to use EJB or Seam as I'm not familiar w/ them. I'm also not familiar enough w/ Spring's HibernateTemplate to realize how it might help...so once I got this to "work", I ran w/ it.

Anyhow...I showed you doGet in my servlet. After I had retrieved the Directory object I was after...I set it to a global variable (eeek!) and then would call it in doPost to make my update (after connecting to a new Session in the DAO, like I demonstrated above.)

I removed the global servlet variable and just did a lookup in doPost to get the record and then did the update...so it all happened in the same Session.

Yeah, it's ugly, I can hear ya now. Any advice would be greatly appreciated.

Thanks Mark!
 
Vinnie Jenks
Ranch Hand
Posts: 207
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Correction in code in my last post.

in my doGet servlet method:

Directory ed = DirectoryProxy.getForBusinessUnit();

...should have been:

Directory ed = DirectoryProxy.getDefault();

I posted before I changed my code...
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic