-
1. Re: Clone hibernate object within conversation still get LazyInitException
kapitanpetko Dec 7, 2009 9:20 AM (in response to allanjun)Cloning/deserialization create a new instance, effectively detaching the object from the Session/Persistence context. That is why you are getting LIEs. Converters (generally) have nothing to do with this.
I don't know how your model is organized, but generally you should be able to implement undo by reloading the root object from the DB. That way all intermediate state(adding/removing from collections, changing properties, etc.) will be lost, and you can start over. If you are saving intermediate results in your wizard, this gets tricky though: you have to trace your steps to implement undo, which is not always easy. You'd better use manual flush and only flush at the end of the wizard. Then you can implement undo using Session.evict/clear() + reload from DB.
HTH
-
2. Re: Clone hibernate object within conversation still get LazyInitException
allanjun Dec 7, 2009 11:26 PM (in response to allanjun)Thanks for the reply Nikolay.
Simple reload can't solve my problem, as I have to save intermediate results.
I understand that the object is detached from session, but why can't it be re-attached back after deserialized if there is session available, do I have to call session.replicate?
I'm using manual flush, but the cancel function I need to implement is not cancelling the whole process but intermediate status. At the moment, I'm tracing all the possible user operations which is such a pain to write. Just thought if I could save(clone/serialize) the object and then re-attach it back to session, it would be a much cleaner approach.
-
3. Re: Clone hibernate object within conversation still get LazyInitException
kragoth Dec 8, 2009 12:32 AM (in response to allanjun)I don't know the complexity or the details of your needs but sometimes a different approach makes your situation a bit easier.
Don't bind your components directly to an attached entity. Use a DTO for each section of the wizard so that all a cancel needs to do is rebuild the DTO for that part of the wizard.
Partial rollbacks are never much fun and I would be trying to avoid them if I could!
I tried to write something to get around your problem, but everytime I started thinking about it I realised that there's really no nice way of doing this.
-
4. Re: Clone hibernate object within conversation still get LazyInitException
kapitanpetko Dec 8, 2009 2:07 AM (in response to allanjun)
Allan Li wrote on Dec 07, 2009 23:26:
I understand that the object is detached from session, but why can't it be re-attached back after deserialized if there is session available, do I have to call session.replicate?Well, I'm not 100% sure about this, but technically you should be able to reattach. The problem is that you have two instances of the same entity (same PK): on in the session, and the one you cloned. Not sure how Hibernate behaves in this case if you try to re-attach, you might have to evict first and re-attach. In any case, there is no easy way to do this, AFAIK. If you object graph is really that complicated, DTO's might be indeed an easier solution.
-
5. Re: Clone hibernate object within conversation still get LazyInitException
allanjun Dec 8, 2009 2:51 AM (in response to allanjun)Thanks for the input guys.
DTO is something I try to avoid. To me, manage DTOs takes probably the same amount effort as cloning/copy entities.
I'll find some time to try evit and re-attach to see how hibernate behaves.
-
6. Re: Clone hibernate object within conversation still get LazyInitException
kragoth Dec 8, 2009 2:59 AM (in response to allanjun)Maybe I'm missing something here but, how is evicting and then reataching going to help you.
Let's assume you have 3 parts to your wizard. So you enter page 1. Evict the entity. Make your changes and go to part 2. Now what? Do you copy/clone your entity from page 1 and make updates to the copy? And so then you copy/clone the entity from page 2 to use in page 3. Is this what you are talking about?
Because if you use the same evicted object in all pages of your wizard then you are not doing partial rollbacks and you might as well just re read from the database every time.
What's your psuedo code for how you plan to handle your wizard?
-
7. Re: Clone hibernate object within conversation still get LazyInitException
allanjun Dec 8, 2009 4:36 AM (in response to allanjun)Yes, I was going to clone the object for each step and pass it on.
Anyway, I tried em.merge hoping that the cloned/deserialized object can be re-attached to the session and won't throw LIE, but it didn't work.
-
8. Re: Clone hibernate object within conversation still get LazyInitException
kragoth Dec 8, 2009 6:21 AM (in response to allanjun)You did evict before cloning right? Otherwise you are serializing your
attached
state and thus LIE's will happen. -
9. Re: Clone hibernate object within conversation still get LazyInitException
allanjun Dec 8, 2009 12:14 PM (in response to allanjun)OK, I got it work!
What I found was if I only use part of the cloned object graph it seems to be fine.
Here is the code,
public class Client implements Serializable { @OneToMany private List<Name> names; @OneToMany private List<Address> addresses; // setters and getters } @Scope(Conversation) public class ClientNameAction { private Client clonedClient; @In @Out private Client client; // Called before name is managed public void init() { clonedClient = (Client)SerializationHelper.clone(client) } /* other methods add/modify/delete names on client.names */ // called when user wants to cancel the changes public void cancel() { // replace messed up names with saved/cloned names client.setNames(clonedClient.getNames()); // client = clonedClient (this won't work) } } @Scope(Conversation) public classs ClientAddressAction { // some methods to manage addresses }
ClientNameAction and ClientAddressAction are steps of the manage client process which is saved to db as one tx.
-
10. Re: Clone hibernate object within conversation still get LazyInitException
kapitanpetko Dec 8, 2009 12:21 PM (in response to allanjun)
Allan Li wrote on Dec 08, 2009 12:14:
OK, I got it work!
What I found was if I only use part of the cloned object graph it seems to be fine.Why doesn't simply calling em.refresh(client) work? That should reload both client and names/addresses from the DB.
-
11. Re: Clone hibernate object within conversation still get LazyInitException
allanjun Dec 9, 2009 6:56 AM (in response to allanjun)
Why doesn't simply calling em.refresh(client) work? That should reload both client and names/addresses from the DB.When user cancel address changes, we still need to keep the changes user made for names, they are different steps of one process.
-
12. Re: Clone hibernate object within conversation still get LazyInitException
kragoth Dec 9, 2009 7:02 AM (in response to allanjun)I don't want to discourage you in your work, but honestly I really think you are setting yourself up for some tough times. When your domain objects change and become more complex this whole clone/evict/partial rollback thing is going to come back and haunt you (or the guy that comes in after you).
Although I disagree with your approach, I wouldn't mind seeing the code out of
professional curiosity
:PI still don't understand how the cloning/evict approach ends up being less work then a straight DTO for this wizard so maybe seeing the code will help.
Cheers,
Tim -
13. Re: Clone hibernate object within conversation still get LazyInitException
kapitanpetko Dec 9, 2009 7:04 AM (in response to allanjun)
Allan Li wrote on Dec 09, 2009 06:56:
When user cancel address changes, we still need to keep the changes user made for names, they are different steps of one process.I see. But then it's not really a wizard. You either finish the wizard and commit or you cancel everything. I guess you could simply flush after the name changes (1st step), go to address change (step 2) and if the user cancels, just reload from DB. That keeps the name changes and discards the address changes. Your use case might be more complicated than that though...
-
14. Re: Clone hibernate object within conversation still get LazyInitException
allanjun Dec 9, 2009 11:52 AM (in response to allanjun)
I guess you could simply flush after the name changes (1st step), go to address change (step 2) and if the user cancels, just reload from DB.Did I say they are two steps of one process? If I had name changes flushed to DB, there is no way to cancel the changes if the whole process is cancelled, I can't keep the tx open for that long time. All changes are flushed within one tx when user click the final save button, there a few other steps.