-->
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: @ManyToMany question
PostPosted: Mon Dec 01, 2008 2:55 pm 
Newbie

Joined: Wed Oct 08, 2008 3:06 pm
Posts: 13
Location: Seattle
Does anyone know why when I do an update on a cross reference table defined by @ManyToMany, hibernate has to delete all related records in the cross reference table and re-insert them again.. Even I don't change anything, it will still fetch all data from the table, delete them and re-insert them again. The ids of those records always change.

How can I just change one of them instead of affecting all of them? Hibernate should know the id of that record already exists and it should only perform an update, but not an insert after a delete.

Thank you.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 01, 2008 3:46 pm 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
If you do not change anything in the relation Hibernate doesn't do anything. A common mistake is to not return exactly the same object from the getter method that Hibernate used when calling the setter method. Eg. user something like that below. No code should never be allowed to change 'foo' to point to some other Set object.

Code:
private Set foo;
public Set getFoo()
{
  return foo;
}
public void setFoo(Set foo)
{
   this.foo = foo;
}


The reason is that Hibernate uses a special Set implementation that keeps track of what you add and remove from the Set so that Hibernate can only submit changes to the database. If the 'foo' is changed to point to some other object Hibernate looses track of changes and as a safety measure deletes everything and re-inserts new rows.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 01, 2008 3:59 pm 
Newbie

Joined: Wed Oct 08, 2008 3:06 pm
Posts: 13
Location: Seattle
nordborg wrote:
If you do not change anything in the relation Hibernate doesn't do anything. A common mistake is to not return exactly the same object from the getter method that Hibernate used when calling the setter method. Eg. user something like that below. No code should never be allowed to change 'foo' to point to some other Set object.

Code:
private Set foo;
public Set getFoo()
{
  return foo;
}
public void setFoo(Set foo)
{
   this.foo = foo;
}


The reason is that Hibernate uses a special Set implementation that keeps track of what you add and remove from the Set so that Hibernate can only submit changes to the database. If the 'foo' is changed to point to some other object Hibernate looses track of changes and as a safety measure deletes everything and re-inserts new rows.


Thank you for the explanation. I think I got your point.

The problem is that I use lazy loading and collection will only be initialized when it displays in view. So when user clicks on the update button without changing anything (I think the collection is already there), the id of each element in the collection is passed to the back end. I need to add them individually to the collection by using another find (database call) to avoid checking if the element is newly added..

Because of the ManyToMany, I have to pass an object to the collection instead of an id.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 01, 2008 6:16 pm 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
So I guess you are actually doing changes to the many-to-many relation. It will be kind of hard to help you unless you post some code, mappings and other relevant information.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 01, 2008 6:49 pm 
Newbie

Joined: Wed Oct 08, 2008 3:06 pm
Posts: 13
Location: Seattle
nordborg wrote:
So I guess you are actually doing changes to the many-to-many relation. It will be kind of hard to help you unless you post some code, mappings and other relevant information.


I am integrating Spring with Hibernate and I take advantage of initBinder method to register a custom editor to convert a collection of ids from view to a collection of objects. Because of ManyToMany, I have to save a collection of objects instead of collection of Long ids. I checked the api for registerCustomEditor and it says that "the PropertyEditor has to create an array or Collection value". I guess that's why I always have a new collection which tells hibernate to delete all related record first and re-insert them even there is nothing changed.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 02, 2008 3:23 am 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
Does that mean that Spring is calling setFoo() with a different collection instead of getFoo().add()/getFoo().remove()? If that is the case then the behavior you see with Hibernate is quite expected.

I have no experience with Spring, but I guess this is more a Spring-related problem than a Hibernate-related problem.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 08, 2008 9:38 pm 
Newbie

Joined: Wed Oct 08, 2008 3:06 pm
Posts: 13
Location: Seattle
nordborg wrote:
Does that mean that Spring is calling setFoo() with a different collection instead of getFoo().add()/getFoo().remove()? If that is the case then the behavior you see with Hibernate is quite expected.

I have no experience with Spring, but I guess this is more a Spring-related problem than a Hibernate-related problem.


I have tried to modify the collection in one session as following..

Code:
        Session session = getHibernateTemplate().getSessionFactory().openSession();
        Transaction tx = session.beginTransaction();
        try {
            A a= (A) session.createCriteria(Aclass).add(Restrictions.eq("id", id)).uniqueResult();
            B b = (B) session.createCriteria(B.class).add(Restrictions.eq("id", programId)).uniqueResult();
            A.getBCollection().remove(b);
            session.update(A);
        } catch (HibernateException he) {
            if (tx != null) {
                tx.rollback();
            }
            throw he;
        } finally {
            tx.commit();
            session.close();
        }


But the id of a record the cross reference table was still changed. Could it be related to the oracle database trigger I defined?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 09, 2008 3:22 am 
Expert
Expert

Joined: Wed Mar 03, 2004 6:35 am
Posts: 1240
Location: Lund, Sweden
Does the above code really works?

According to the API documenation for the Session.update() method an exception should be thrown if it is called with an argument that is already attached to the session. In any case, there is no need to call Session.update().

I am not sure that the call to tx.commit() should be placed inside the finally clause. If there is an error you will end up calling both rollback() and then commit().

Regarding the trigger, I have no idea.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 09, 2008 4:29 pm 
Newbie

Joined: Wed Oct 08, 2008 3:06 pm
Posts: 13
Location: Seattle
nordborg wrote:
Does the above code really works?

According to the API documenation for the Session.update() method an exception should be thrown if it is called with an argument that is already attached to the session. In any case, there is no need to call Session.update().

I am not sure that the call to tx.commit() should be placed inside the finally clause. If there is an error you will end up calling both rollback() and then commit().

Regarding the trigger, I have no idea.


Thank you for the suggestion, but even I got rid of those, hibernate still tried to delete first and then did a insert instead of just delete the proper record only...

Hibernate: delete from A_B where A_ID=?
Hibernate: insert into A_B (A_ID, B_ID) values (?, ?)


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.