-->
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.  [ 8 posts ] 
Author Message
 Post subject: Bidirectional many-to-many on same entity
PostPosted: Thu Jan 28, 2010 9:12 am 
Newbie

Joined: Thu Jan 28, 2010 5:50 am
Posts: 5
Hello everybody,
I am struggling for a while now with a mapping problem: I want to realize a bidirectional many-to many relationship on the same entity.
I have a User that can have friends, which are of the type User as well. My mapping looks like that:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-cascade="all">
   <class name="com.objecttrax.tracking.domain.User" table="user">
      <id name="id" type="long">
         <generator class="native" />
      </id>
      <property name="username" unique-key="true" />
      <property name="password" />
      <array name="friends" table="tracking_user_friends" inverse="true">
         <key column="friend_id" />
         <index column="id" />
         <many-to-many column="user_id"
            class="com.objecttrax.tracking.domain.User" />
      </array>
      <array name="friendOf" table="tracking_user_friends" cascade="none">
         <key column="user_id" />
         <index column="id" />
         <many-to-many column="friend_id"
            class="com.objecttrax.tracking.domain.User" />
      </array>
   </class>
</hibernate-mapping>



On the first look that works. I am testing the following scenario:
I have 3 users, which are persisted:
user1
user2
user3

I am adding the following on the friendOf site of the relationship of the users and persist it:
user1.friendOf => [user2,user3]
user2.friendOf => [user3]

After persisting I test the friends site of the relationship and I get this:
user1.friends => [] (OK)
user2.friends => [user1] (OK)
user3.friends => [user2] (NOT OK) expected: [user1, user2]

It seems to me that index (<index column="id"/>) is causing the problem, but I don't know a better way for the mapping.
Does anybody has idea?

Thanks for your help.
Best regards,
Jens

---
Jens Laufer
http://www.objectworkz.org


Top
 Profile  
 
 Post subject: Re: Bidirectional many-to-many on same entity
PostPosted: Thu Jan 28, 2010 9:35 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
As I know, inverse="true" is for use with bidirectional OneToMany associations, not with ManyToMany associations.
Try to remove the inverse="true" definition.


Top
 Profile  
 
 Post subject: Re: Bidirectional many-to-many on same entity
PostPosted: Thu Jan 28, 2010 9:47 am 
Newbie

Joined: Thu Jan 28, 2010 5:50 am
Posts: 5
Thanks for your quick answer, I removed the inverse, but I am still having the same problem.


Top
 Profile  
 
 Post subject: Re: Bidirectional many-to-many on same entity
PostPosted: Thu Jan 28, 2010 10:22 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
Sorry, I was wrong in my previous posting.
On Bidirectional many-to-many association it is mandatory to declare one side with inverse="true".

Did you remember to set both end of the association when establishing the association?


Top
 Profile  
 
 Post subject: Re: Bidirectional many-to-many on same entity
PostPosted: Thu Jan 28, 2010 10:44 am 
Newbie

Joined: Thu Jan 28, 2010 5:50 am
Posts: 5
Do I have to set both ends. I thought I just have set the one end, where I have inverse="false"

Here the test code I use:
Code:
                User user1 = new User();
      user1.setUsername("friend1");
      dao.saveOrUpdate(user1);

      User user2 = new User();
      user2.setUsername("friend2");
      user2.setFriendOf(new User[] { user1 });
      dao.saveOrUpdate(user2);

      object = new User();
      object.setUsername("username");
      object.setFriendOf(new User[] { user1, user2 });
      dao.saveOrUpdate(object);

      User actual = dao.get(object.getId());
      User loadedUser1 = dao.get(user1.getId());

      assertEquals("friend1", actual.getFriendOf()[0].getUsername());
      assertEquals("friend2", actual.getFriendOf()[1].getUsername());
      assertEquals(2, loadedUser1.getFriends().length);
      assertEquals("username", loadedUser1.getFriends()[0]
            .getUsername());
      assertEquals("friend2",  loadedUser1.getFriends()[1]
            .getUsername());

      // Friends cannot be removed from "to" site
      loadedUser1.setFriends(new User[] {});
      dao.saveOrUpdate(loadedUser1);

      loadedUser1 = dao.get(user1.getId());
      actual = dao.get(object.getId());

      assertEquals("friend1",actual.getFriendOf()[0].getUsername());
      assertEquals("friend2", actual.getFriendOf()[1].getUsername());
      assertEquals(2, loadedUser1.getFriends().length);
      assertEquals("username", loadedUser1.getFriends()[0]
            .getUsername());
      assertEquals("friend2", loadedUser1.getFriends()[1]
            .getUsername());

      // Friends can be removed "from" site
           object.setFriendOf(new User[] {});
      dao.saveOrUpdate(object);

      loadedUser1 = dao.get(user1.getId());
      actual = dao.get(object.getId());

      assertEquals(1, loadedUser1.getFriends().length);
      assertEquals("friend2", loadedUser1.getFriends()[1]
            .getUsername());
      assertEquals(0, actual.getFriendOf().length);


Top
 Profile  
 
 Post subject: Re: Bidirectional many-to-many on same entity
PostPosted: Thu Jan 28, 2010 10:48 am 
Newbie

Joined: Thu Jan 28, 2010 5:50 am
Posts: 5
...and the DAO, which is a standard HibernateDao supportetd by Spring:
Code:
jecttrax.tracking.domain.User;

public class UserDaoHibernateImpl extends HibernateDaoSupport implements
      UserDao {

   public void delete(User object) {
      getHibernateTemplate().delete(object);
   }

   public User get(long id) {
      return (User) getHibernateTemplate().get(User.class, id);
   }

   public User saveOrUpdate(User object) {
      User loadedLocation = get(object.getId());
      getHibernateTemplate().saveOrUpdate(object);
      return object;
   }
}


Top
 Profile  
 
 Post subject: Re: Bidirectional many-to-many on same entity
PostPosted: Thu Jan 28, 2010 10:51 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
>>Do I have to set both ends. I thought I just have set the one end, where I have inverse="false"

Hibernate documentation states that both ends must be set, even when working with inverse="false".

Anyway I guess that it wrong to refer to the same index column "id" twice (= from both sides)

Code:
<index column="id" />


Moreover the usage of <array> for associations is the last choice.
Hiberante documentation (and me too) suggests to use <set> of instead.
In this case you don't need the index column.


Top
 Profile  
 
 Post subject: Re: Bidirectional many-to-many on same entity
PostPosted: Fri Jan 29, 2010 9:24 am 
Newbie

Joined: Thu Jan 28, 2010 5:50 am
Posts: 5
Thanks.
I am using a Set now, with the additional advantage, that lazy loading is supported.


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