-->
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.  [ 11 posts ] 
Author Message
 Post subject: many-to-many on the same class
PostPosted: Thu Mar 02, 2006 1:23 pm 
Newbie

Joined: Thu Mar 02, 2006 1:08 pm
Posts: 6
Hi, I've got a problem with saving a many-to-many association.
My object is a User and can have associated a Set of other User (the friends).
I want that the association is unidirectional (UserA is friend of UserB and not automatically the vice-versa).

This is my mapping of User :


<class name="User" table="user">
<id unsaved-value="-1" name="id" type="int" column="id">
<generator class="sequence">
<param name="sequence">seq_users</param>
</generator>
</id>
<set name="friends"
table="user_friends"
lazy="true"
>
<key column="iduser"/>
<many-to-many class="User" column="idfriend"/>
</set>
</class>

and the class of User is this

public class User implements Serializable{

private int id=-1;
private Set friends = new HashSet();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}

public int getFriends() {
return friends;
}
public void setFriends(int friends) {
this.ifriends = friends;
}
}

I create a join table on the db with the two column for the fk.
If I add a record directly on the db and after try to load the user i found
the correct friends (so I think the mapping is correctly).
But if I load the User, add the friend and save, the state is not persist on the db.
Follow the java code:
Session sess =.....;
User us1= (User ) sess.get(User .class,new Integer(0));
assertTrue(us1A.getFriends().size==0)
User us2= (User ) sess.get(User .class,new Integer(298));
assertTrue(us1!=null && us2!=null);
us.getFriends().add(us2);
sess.saveOrUpdate(ut);

Session sess2 = ....;
User us1A = (User) sess2.get(User .class,new Integer(0));
assertTrue(us1A.getFriends().size==1) <---- FAIL

Can someone help me?
Thanks in advance!

Mauro















[b]3.1[/b]

[b]Mapping documents:[/b]

[b]Code between sessionFactory.openSession() and session.close():[/b]

[b]Full stack trace of any exception that occurs:[/b]

[b]Name and version of the database you are using:[/b]

[b]The generated SQL (show_sql=true):[/b]

[b]Debug level Hibernate log excerpt:[/b]


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 02, 2006 7:00 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
This isn't a many-to-many, this is a one-to-many. One user has many friends, but one friend doesn't have a set of many users. It could be implemented that way, but there'd be a join table involved. The User table has a column refering to the one and only other user with which this user is friendly. This user may have other friends, but they'd all have their friendId column pointing to him.

First thing to sort out is whether you actually want a many-to-many or not. If you don't, then all you have to do to your mapping to get it to work is to change the many-to-many to be one-to-many, drop the column attribute, and change the key column to idfriend.

To implement a true many-to-many, you'll need a join table containing iduser and idfriend, then drop the idfriend column from the user table. Section 6.2, 2Collection Mappings", of the ref docs will guide you the rest of the way.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 4:11 am 
Newbie

Joined: Thu Mar 02, 2006 1:08 pm
Posts: 6
Hi tenwit, this is a many-to-many associations, and I've got just a join-table.
It's a many-to-many and I try to explain in one example.
UserA is friend of UserB and UserC
UserB is friend of UserD,UserE and UserF.
UserD is friend of UserC.

In the join-table "user_friends" we can found this record

iduser-idfriend
---------------------------
UserA-UserB
UserA-UserC
UserB-UserD
UserB-UserE
UserB-UserF
UserD-UserC
---------------------------
If I set this record in the database and try to retrieve the UserA,UserB and UserD I found populate the friends in the correct way.
My problem is when I save it the Set is not persist.

Sorry for my english that probably doesn't help my explanation.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 5:52 am 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Reread my earlier post. It is a one-to-many. It's just a one-to-many-to-manymore-to... I know you're thinking of it as a many-to-many, but without the join table (and you don't have a join table, you just have the entity table) it isn't a many-to-many.

I understand that you are achieving many-to-many after a fashion, but it's not what relational DB people, ORM people, or more specifically hibernate people, call many-to-many. One user can have many subusers, but only one superuser (where sub-user is another user referring to this user, and a superuser is a user that this user is referring to). In order for it to be tryue many-to-many, one user must be able to have many super-users.

What I posted earlier is correct. If you follow my guidelines, it will work. The correct way to implement many-to-many is with a UserFriend table: UserA <-> UserFriend <->UserB. UserFriend will have two columns, UserId and UserId.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 03, 2006 6:43 am 
Newbie

Joined: Thu Mar 02, 2006 1:08 pm
Posts: 6
Uff, I think that my terrible english doesn't help me! :((
Why you say that I haven't a join table?
I try to explain another time, because probably I don't give you all the information .
Db Schema:
This is the entity table:
-----------------------------------------------------------
CREATE TABLE user(
id bigint NOT NULL
);
ALTER TABLE user
ADD CONSTRAINT pk_user PRIMARY KEY (id);
-----------------------------------------------------------
And this is the Join Table:
-----------------------------------------------------------
CREATE TABLE user_friends(
iduser bigint,
idfriend bigint
);
ALTER TABLE ONLY user_friends
ADD CONSTRAINT fk_iduser FOREIGN KEY (iduser ) REFERENCES user(id);
ALTER TABLE ONLY user_friends
ADD CONSTRAINT fk_idfriend FOREIGN KEY (idfriend ) REFERENCES user(id);
--------------------------------------------------------------
This sentence that you write is not correct :
"One user can have many subusers, but only one superuser (where sub-user is another user referring to this user, and a superuser is a user that this user is referring to). In order for it to be tryue many-to-many, one user must be able to have many super-users. "

One user is able to have many super-users. And in the following example (the same that I've just posted)

UserA-UserB
UserA-UserC
UserB-UserD
UserB-UserE
UserB-UserF
UserD-UserC

you can see that UserC has got (using your denomination) two "super-users", UserA and UserC.
So I think this is a many-to-many association.

In the mapping of my first post you can find in the <set> the table "user_friends" for show that there is the join-table.

I think that my problem is on the attribute of the mapping or probably I haven't understand your post.


Thanks a lot for the help and sorry another time for the incromprension.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 05, 2006 4:58 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Many apologies, I completely misread your first post. Sorry for wasting all that time. I'll wear a pointy hat with a big "D" on it and sit in the corner all morning.

I have a question about your sample java code:
Code:
User us1= (User ) sess.get(User .class,new Integer(0));
assertTrue(us1A.getFriends().size==0)
User us2= (User ) sess.get(User .class,new Integer(298));
assertTrue(us1!=null && us2!=null);
us.getFriends().add(us2);
sess.saveOrUpdate(ut);
I'm guessing that there are some typos in here? Do you have the correct references to us1 the whole way through, or do you really have those mistakes with variables? You refer to us1A even though it's not loaded until later, and there's a variable "us" that isn't mentioned anywhere else. First thing to do is to rerun your code with the correct variables, if they're wrong. You should also put a sess.flush after the saveOrUpdate.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 06, 2006 4:29 am 
Newbie

Joined: Thu Mar 02, 2006 1:08 pm
Posts: 6
Don't worry, it can happens.
the java code is wrong only because I translate it from italian name to english name (Utente->User) and so in the translation I wrong something.

The correct one is this :

Session sess =.....;
User us1= (User ) sess.get(User .class,new Integer(0));
assertTrue(us1.getFriends().size==0)
User us2= (User ) sess.get(User .class,new Integer(298));
assertTrue(us1!=null && us2!=null);
us1.getFriends().add(us2);
sess.saveOrUpdate(ut);
sess.flush; <--Added, but without changes.
sess.close();


Session sess2 = ....;
User us1A = (User) sess2.get(User .class,new Integer(0));
assertTrue(us1A.getFriends().size==1) <---- FAIL

I think the problem is in the mapping, but only in the save moment.
I try with the inverse="true" but with no success.

Thanks .

Mauro


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 06, 2006 5:07 am 
Newbie

Joined: Thu Mar 02, 2006 1:08 pm
Posts: 6
I wrong it another time, the correct is this.

Session sess =.....;
User us1= (User ) sess.get(User .class,new Integer(0));
assertTrue(us1.getFriends().size==0)
User us2= (User ) sess.get(User .class,new Integer(298));
assertTrue(us1!=null && us2!=null);
us1.getFriends().add(us2);
sess.saveOrUpdate(us1);
sess.flush; <--Added, but without changes.
sess.close();


Session sess2 = ....;
User us1A = (User) sess2.get(User .class,new Integer(0));
assertTrue(us1A.getFriends().size==1) <---- FAIL

I try also make the modify in a transaction and committing it before closing the session but doesn't work.
The strange is that this case is equal to the example of Person and Event in the hibernate reference "1.3.2. A unidirectional Set-based association".
But wit me doesn't work!
Probably I make other mistakes.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 06, 2006 4:50 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
You could try explicitly referring to the id column/property when needed, instead of relying on it being defaulted:
Code:
<set name="friends" table="user_friends" lazy="true">
  <key column="iduser" property-ref="id"/>
  <many-to-many column="idfriend" property-ref="id" class="User" fetch="select"/>
</set>
I also added fetch="select", in case hibernate is going down some infinite recursion path when joining, and failing at that stage. Though seeing as your mapping is loading things correctly, that's unlikely.

Your mapping looks pretty good to me though. You may be forced to debug into the hibernate code to find out why the collection isn't being persisted correctly.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 07, 2006 4:44 am 
Newbie

Joined: Thu Mar 02, 2006 1:08 pm
Posts: 6
Ok, now it's my time to wear a pointy hat with a big "D" on it and sit in the corner all morning.
My problem is that I added an inverse="true" to the mapping and I never put it on the post.
Without this it works perfectly.

Sorry for the waste of time!


Top
 Profile  
 
 Post subject: Thanks both of you
PostPosted: Fri Apr 21, 2006 12:36 pm 
Newbie

Joined: Fri Feb 20, 2004 2:33 pm
Posts: 3
Location: Valencia, Spain
Thank you a lot. I had the same problem and thanks to your
"waste-of-time" discussion I solved it.

Simon


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