-->
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.  [ 14 posts ] 
Author Message
 Post subject: many-to-many mapping returns empty set
PostPosted: Sat Nov 26, 2005 4:39 am 
Newbie

Joined: Sat Nov 26, 2005 4:32 am
Posts: 8
Hello all!

I am trying to do something extremely easy (as I read from the manuals) but it seems that I cannot achieve it. I am trying to create a many-to-many mapping between to tables.

A) I have a table called users:

Code:
mysql> select * from users;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | admin    | admin    |
|  2 | axel     | axel     |
|  3 | manos    | manos    |
+----+----------+----------+
3 rows in set (0.00 sec)


I have another table called artists:

Code:
mysql> select * from artist;
+----+--------------------------+
| id | artist                           |
+----+--------------------------+
|  1 | Jim Morrison          |
|  2 | John Lennon         |
|  3 | ACDC              |
|  4 | Led Zeppelin          |
+----+--------------------------+
4 rows in set (0.01 sec)


These two tables are connected by a third table called user_artist: (f_user_id is a foreign key to the table user and column id and f_artist_id is a foreign key to the table artist and column id)

Code:
mysql> select * from user_artist;
+-----------+-------------+----+
| f_user_id | f_artist_id | id |
+-----------+-------------+----+
|         1 |           1 |  1 |
|         1 |           2 |  2 |
|         1 |           3 |  3 |
|         1 |           4 |  4 |
|         2 |           1 |  5 |
|         2 |           3 |  6 |
|         3 |           2 |  7 |
+-----------+-------------+----+
7 rows in set (0.00 sec)


B) The corresponding hibernate mappings are as follows:

a) for the users table:

Code:
<hibernate-mapping>
   <class name="com.am.struts.wamp3.app.business.Artist" table="artist">
      <id name="id" column="id" type="java.lang.Integer">
           <generator class="native"/>
      </id>
       <property name="artist" column="artist" type="java.lang.String" />
      <set name="users" table="user_artist" lazy="false" cascade="save-update">
         <key column="f_artist_id"/>
         <many-to-many class="com.am.struts.wamp3.user.business.SystemUsers" column="id"/>
      </set>   
   </class>
</hibernate-mapping>


b) for the artist table:

Code:
<hibernate-mapping>
   <class name="com.am.struts.wamp3.user.business.SystemUsers" table="users">
      <id name="id" column="id" type="java.lang.Integer">
           <generator class="native"/>
      </id>
       <property name="username" column="username" type="java.lang.String" />
      <property name="password" column="password" type="java.lang.String" />
      <set name="artists" table="user_artist" lazy="false" cascade="save-update">
         <key column="f_user_id"/>
         <many-to-many class="com.am.struts.wamp3.app.business.Artist" column="id"/>
      </set>
   </class>
</hibernate-mapping>

c) for the user_artist table there is no hibernate mapping, since it is referenced within the previous two mappings.

C) Finally, regarding the two java classes appart from the setters and getters of the String fields I also have the following methods:

i) Artist.java

Code:
public Set getusers()
{ return this.users; }
   
public void setusers(Set users)
{ this.users = users; }


ii) SystemUsers.java

Code:
public Set getartists()
{ return this.artists;    }
   
public void setartists(Set artists)
{ this.artists = artists; }


D) The code in java that should produce a list of artists belonging to a specific user is as follows:

Code:
Session session = null;
Transaction tx = null;

session = HibernateSessionFactory.currentSession();
tx = session.beginTransaction();

List l = session.createQuery("from SystemUsers su where su.id = 3").list();
SystemUsers su = (SystemUsers)l.get(0);

Set arti = su.getartists();
                   
tx.commit();
session.close();
return arti;


But this returns an empty Set.

Could you please help me out here.

Thank you in advance
axelmangr


Top
 Profile  
 
 Post subject:
PostPosted: Sat Nov 26, 2005 4:58 am 
Expert
Expert

Joined: Mon Jul 04, 2005 5:19 pm
Posts: 720
Can you post the hashCode() and equals() implemenatations for the Artists?


Top
 Profile  
 
 Post subject:
PostPosted: Sat Nov 26, 2005 6:00 am 
Newbie

Joined: Sat Nov 26, 2005 4:32 am
Posts: 8
I haven't implemented these two methods. Is it obligatory to do so? Other tables mappings I have in my application (simple select statemts) work without them! Please advise

Thanx for the immediate reply.

axelmangr


Top
 Profile  
 
 Post subject:
PostPosted: Sat Nov 26, 2005 8:11 am 
Newbie

Joined: Tue Nov 01, 2005 5:39 pm
Posts: 11
What I had to do to get this working was create a class for the lookup table with properties to represent the foreign keys. Here is a cheat sheet I found for a quick reference.

http://ndpsoftware.com/HibernateMappingCheatSheet.html

scroll down to the Composite Id section. When I defined my set for the collection I had to use the composite id as my key property.
Here is something else you may run into. If you want to order-by an of the properties of your concrete classes, hibernate with create a query that looks for the order-by table in your composite table columns. I haven't figured out how to get that one to work yet, at least not without sorting outside of hibernate.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Nov 26, 2005 2:09 pm 
Expert
Expert

Joined: Mon Jul 04, 2005 5:19 pm
Posts: 720
blaplante - "lookup table" ? He has two "entity tables" and an "association table". I'm getting a 404 from that link.

axelmangr - look at the bottom of this http://www.hibernate.org/hib_docs/v3/re ... l-join-m2m . see how the name of the association table is doesn't come into play in this case?


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 27, 2005 6:16 am 
Newbie

Joined: Sat Nov 26, 2005 4:32 am
Posts: 8
Hi!

I 've already seen this but haven't tried it so far. I did but I get the same outcome.

Here is how my hbm.xml look like now:

Code:
<class name="com.am.struts.wamp3.app.business.Artist" table="artist">
    <id name="artist_id" column="artist_id">
        <generator class="native"/>
    </id>
    <set name="users" inverse="true">
        <key column="artist_id"/>
        <many-to-many column="user_id" class="com.am.struts.wamp3.user.business.SystemUsers"/>
    </set>
</class>


and

Code:
<class name="com.am.struts.wamp3.user.business.SystemUsers" table="users">
    <id name="user_id" column="user_id">
        <generator class="native"/>
    </id>
      <property name="username" column="username" type="java.lang.String" />
      <property name="password" column="password" type="java.lang.String" />
    <set name="artists">
        <key column="user_id"/>
        <many-to-many column="artist_id" class="com.am.struts.wamp3.app.business.Artist"/>
    </set>
</class>


And the query:
Code:
List l = session.createQuery("from SystemUsers su where su.id = 3").list();
SystemUsers su = (SystemUsers)l.get(0);
Set arti = su.getartists();
return arti;


But I still get An empty collection. And anyway I really don't understand how the connection between the tables is established without the third table referencing them.

Please help me out here

Thanx in advace for your replies

axelmangr


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 27, 2005 9:53 am 
Expert
Expert

Joined: Mon Jul 04, 2005 5:19 pm
Posts: 720
Well, there is certainly nothing wrong w/ a many-to-many, but I tend to expose the association table to the domain model. see http://www.hibernate.org/hib_docs/v3/re ... tices.html and part reading "exotic association mappings" .


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 27, 2005 11:43 am 
Newbie

Joined: Sat Nov 26, 2005 4:32 am
Posts: 8
I read what you suggested. If I follow the advice and replace the many-to-many with two one-to-many I go back to my original configuration and get an empty resultset. How can I overcome this problem and really get the desired results? I have looked at my code and cannot find something wrong there. Can you help me out here?

Thanx in advance
axelmangr


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 27, 2005 2:19 pm 
Expert
Expert

Joined: Mon Jul 04, 2005 5:19 pm
Posts: 720
take a look at section 8.3.4 - http://www.hibernate.org/hib_docs/v3/re ... l-join-m2m . See how there is a table attribute for the set? what happens if you get more specific with that?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 28, 2005 2:15 pm 
Newbie

Joined: Sat Nov 26, 2005 4:32 am
Posts: 8
I have already checked what you mention. Actually you have already pointed towards this direction. I have already followed your advice but could not get the wanted results. Than's why I posted my code previously. I have exacly followed what is mentioned on the html you mention but still I get an empty result set.

Any ideas would be appreciated

Thanx in advance
axelmangr


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 30, 2005 4:17 pm 
Newbie

Joined: Wed Nov 30, 2005 4:13 pm
Posts: 12
I think it should be like this:
<hibernate-mapping>
<class name="com.am.struts.wamp3.app.business.Artist" table="artist">
<id name="id" column="id" type="java.lang.Integer">
<generator class="native"/>
</id>
<property name="artist" column="artist" type="java.lang.String" />
<set name="users" table="user_artist" lazy="false" cascade="save-update">
<key column="f_artist_id"/>
<many-to-many class="com.am.struts.wamp3.user.business.SystemUsers" column="f_user_id"/>
</set>
</class>
</hibernate-mapping>


b) for the artist table:

<hibernate-mapping>
<class name="com.am.struts.wamp3.user.business.SystemUsers" table="users">
<id name="id" column="id" type="java.lang.Integer">
<generator class="native"/>
</id>
<property name="username" column="username" type="java.lang.String" />
<property name="password" column="password" type="java.lang.String" />
<set name="artists" table="user_artist" lazy="false" cascade="save-update">
<key column="f_user_id"/>
<many-to-many class="com.am.struts.wamp3.app.business.Artist" column="f_artist_id"/>
</set>
</class>
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 30, 2005 4:30 pm 
Newbie

Joined: Wed Nov 30, 2005 4:13 pm
Posts: 12
you also have to add the inverse attribute set to true to one of <set> tags, simply choose one
for example:
<set name="artists" table="user_artist" lazy="false" cascade="save-update" inverse="true" >


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 30, 2005 4:40 pm 
Newbie

Joined: Wed Nov 30, 2005 4:13 pm
Posts: 12
I don't know much about hibernate. I have a question:
you get instance of artist and you specify that it has to be loaded locked,
so when I get Set artistSet = artist.getArtists(); the artists in artistSet will be locked too? or maybe there is an overloaded method getArtists(LockMode.UPGRADE) ?


Top
 Profile  
 
 Post subject:
PostPosted: Sun Dec 04, 2005 10:03 am 
Newbie

Joined: Sat Nov 26, 2005 4:32 am
Posts: 8
I finally figered it out. The correct way of implementing what I need is the following: (I post it just in case it helps someone)

Code:
<hibernate-mapping>
<class name="com.am.struts.wamp3.app.business.Artists" table="artists">
      <id name="artist_id" column="artist_id" type="java.lang.Integer">
           <generator class="native"/>
      </id>
       <property name="artist" column="artist" type="java.lang.String" />
      <set name="users" table="user_artist" lazy="false" cascade="save-update">
         <key column="f_artist_id"/>
         <many-to-many class="com.am.struts.wamp3.user.business.SystemUsers" column="f_user_id"/>
      </set>   
   </class>
</hibernate-mapping>


Code:
<hibernate-mapping>
<class name="com.am.struts.wamp3.user.business.SystemUsers" table="users">
   <id name="user_id" column="user_id" type="java.lang.Integer">
        <generator class="native"/>
   </id>
   <property name="username" column="username" type="java.lang.String" />
   <property name="password" column="password" type="java.lang.String" />
   <set name="artists" table="user_artist" lazy="false" cascade="save-update" inverse="true">
      <key column="f_user_id"/>
      <many-to-many class="com.am.struts.wamp3.app.business.Artists" column="f_artist_id"/>
   </set>
</class>
</hibernate-mapping>


If someone needs more explanations feel free to ask...

jbialobr:

Quote:
I don't know much about hibernate. I have a question:
you get instance of artist and you specify that it has to be loaded locked,
so when I get Set artistSet = artist.getArtists(); the artists in artistSet will be locked too? or maybe there is an overloaded method getArtists(LockMode.UPGRADE) ?


I didn't quite get you there. What exaclty do you mean by loaded locked?


Thanx a lot for your help guys

axelmangr


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