-->
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.  [ 9 posts ] 
Author Message
 Post subject: Merge or Update?
PostPosted: Thu Dec 08, 2005 1:50 pm 
Newbie

Joined: Fri Dec 02, 2005 2:48 pm
Posts: 13
Hibernate version: 3.0

I just want to update some attributes of an Parent object. That Parent object has a collection of Child objects, but I don't want to update them... I want to keep these Children objects in the Parent and update the others attributes of Parent object like name and password. Ok, here is my code:


MyAction.execute():
-----------------------------------------------
Code:
Parent p = new Parent();
p.setName( request.getParameter("name") );
p.setpassword( request.getParameter("password") );

myService.updateParent(p);


MyService.updateParent(Parent p):
-----------------------------------------------
Code:
parentDao.update(p);


ParentDao.update(Parent p):
-----------------------------------------------
Code:
// How can I update only the name and password attributes, but keeping all Children object associated with the Parent?
// a) By using merge, the Parent object will loose all the Children objects!
// b) By using update, it'll throw an org.hibernate.NonUniqueObjectException



Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 08, 2005 2:05 pm 
Newbie

Joined: Fri Dec 02, 2005 2:48 pm
Posts: 13
The only way I can see to do this is by loading the object first and transfer all new data from the Parent (in the parameter) to the other Parent loaded from hibernate.

MyService
Code:
public void updateParent(Parent p){

   Parent parent = parentDao.load(parent);

   parent.setName( p.getName() );
   parent.setPassword( p.getPassword() );
}


But I don't think it is the best way to do that...


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 08, 2005 3:02 pm 
Beginner
Beginner

Joined: Wed Jul 06, 2005 4:51 pm
Posts: 27
Don't set cascade options on the relationship

or are you using composite elements instead?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 08, 2005 3:23 pm 
Newbie

Joined: Fri Dec 02, 2005 2:48 pm
Posts: 13
kshreeram wrote:
Don't set cascade options on the relationship


I don't believe that it is a good way to solve the problem because I would need the 'cascade' attribute when I have to save/update all Children objects.

Do you have another idea?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 08, 2005 3:57 pm 
Regular
Regular

Joined: Thu Oct 27, 2005 8:06 am
Posts: 55
Location: München, Germany
If you want to update the parent, then get/load/find the parent, make your necessary updates on the POJO retrieved, and save that object. Hibernate will detect by itself that you didn't change the children, and won't bother about them. If you didn't map the parent-child relationship as lazy="false", the children won't even have been read (unless you accessed them in your Java code).

That NonUnique thing might have the following reason. Assume you had the parent object attached to a previous Hibernate session, and kept it in memory after the session, so that it became detached. Assume you loaded it again in a new session, but issued the Hibernate save operation on the object you had still in memory from the last session. Then Hibernate detects that there are two copies of the same object, and complains.

If that's the case, not loading the object again and trying to save the detached one will also lead to an exception. The right way will be to either make the object persistent again by issuing a lock operation, or to forget about the detached one completely and just operating on the one freshly loaded.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 08, 2005 10:38 pm 
Newbie

Joined: Fri Dec 02, 2005 2:48 pm
Posts: 13
Thomas Matzner wrote:
If you want to update the parent, then get/load/find the parent, make your necessary updates on the POJO retrieved, and save that object. Hibernate will detect by itself that you didn't change the children, and won't bother about them.


So, the following code just do that, right?

MyService
Code:
public void updateParent(Parent p){

   Parent parent = parentDao.load(parent);

   parent.setName( p.getName() );
   parent.setPassword( p.getPassword() );
}


But it seems a bit cumbersome... imagine that the Parent object has thousands attributes... I'll have to call set and get for each attribute to transfer data.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 09, 2005 12:45 am 
Regular
Regular

Joined: Thu Oct 27, 2005 8:06 am
Posts: 55
Location: München, Germany
I still don't understand whether you have any special requirements. Your code doesn't update a parent, but it copies Parent p to a newly constructed Parent parent. If a copy is what you need (i.e. if your post condition is to have two Parent objects), proceed as indicated by your code. Concerning getting and setting all those attributes, have a look at the Java deep and shallow copy mechanisms, which might relieve you from writing all those cumbersome lines.

When copying, it's up to your application how to set the children of the newly constructed parent. The requirements for this come from your problem domain. Should p's children objects become parent's children? Should they continue to be children of parent, which would make the parent - child relationship many-to-many? Should copies of the parent's children become p's children? That's an issue you have to handle in your Java code, after which Hibernate will persist the parent - children graph for you.

In any case, I would call this operation copyParent instead of updateParent.

If, however, your initial requirement is an update instead of a copy, your code should work on the initial parent alone without creating a new one. The sequence is something like

Code:
get(p); // or another operation getting p from the database, or lock(p) if p is detached
p.setSomeAttributes(newValues);
saveOrUpdate(p);


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 09, 2005 6:48 am 
Newbie

Joined: Fri Dec 02, 2005 2:48 pm
Posts: 13
Thomas Matzner wrote:
If, however, your initial requirement is an update instead of a copy, your code should work on the initial parent alone without creating a new one. The sequence is something like

Code:
get(p); // or another operation getting p from the database, or lock(p) if p is detached
p.setSomeAttributes(newValues);
saveOrUpdate(p);



Yes, my requiment is that. An update instead of copy.
But remember that I have the Presentation Layer (action class) and Business Layer (service class). The first newly Parent is created in the Action to hold all parameters coming from request, like that:

MyAction.execute():
-----------------------------------------------
Code:
Parent p = new Parent();
p.setName( request.getParameter("name") );
p.setpassword( request.getParameter("password") );

myService.updateParent(p);


At the moment the service method is called it pass the Parent object that is ready to be update at the other side (service class). I'd like to just take the Parent object passed in the parameter of the method and "merge" with persistent object, that is, update only the fields that have been modified in the Action class.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 12, 2005 7:02 pm 
Regular
Regular

Joined: Thu Oct 27, 2005 8:06 am
Posts: 55
Location: München, Germany
I still don't see the necessity of that duplicating, and I suspect it's the cause for all that trouble.

When separating a business tier from a GUI tier, there are basically two ways. One is that the GUI tier delegates to the original business object. That's simplest in terms of ease of coding. You appear not to be able to access your business object from the GUI tier. What you are doing looks like some sort of Data Transfer Object approach. A DTO has a different structure from any of the business objects (otherwise it wouldn't be needed). But then, of course, you can't update the DTO directly, just because it has a different structure. So the DTO scheme is

Code:
create or read business object b
derive DTO d from b (and other objects, possibly)
manipulate d in presentation layer
if b still in memory
   lock(b)
else
   get b from database
re-convert DTO to b (and other objects)
store b


The point is that it's always the same object b that has been read or locked that is also updated.

Another problem that appears whenever adding or removing child elements in a set is equality. It already appears when you have one and the same Java object that got children in a set in one Hibernate session, and adds children in another session. In this case, standard equality defined by object identity doesn't work any more, but you have to define a fitting equals method. See http://www.hibernate.org/109.html


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

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.