-->
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.  [ 25 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Can't get many-to-many bidi relationship to work.
PostPosted: Fri Feb 09, 2007 5:27 pm 
Newbie

Joined: Fri Feb 09, 2007 3:24 pm
Posts: 3
Hi,

i got a problem with a many-to-many bidirectional relationship. I got User and Group classes. A user can be part of many groups and a group can hold many users. I have mapped the User/Group classes as specified below. My problem is, that the table "br_usergroup" which holds the relations between users and groups does not receive an entry, when I do the following:

Code between sessionFactory.openSession() and session.close():
Code:
   User user = new User();
        user.Login = "kork";
        user.Password = "blah";
       

        Group p = new Group();
        p.Name = "Gods";

        Group q = new Group();
        q.Name = "Ubergods";
        q.ParentGroup = p;
        user.Groups.Add(q);
        q.Users.Add(user);
        user.Groups.Add(p);
        p.Users.Add(user);

ISession session = factory.openSession();
session.SaveOrUpdate( p );
session.SaveOrUpdate( q );
session.SaveOrUpdate( user );
session.Close();



The entries in br_user and br_group tables are all correctly made, just the entries in br_usergroup are not showing up. I am pretty sure i am missing something in the mapping, but i read a lot of tutorials and to me the mapping xml looks ok. Any help is appreciated.



Hibernate version:
nhibernate 1.0.4.0

Mapping documents:

Mapping for User:
Code:
<?xml version="1.0" encoding="utf-8"?>
<!--Generated by NHibernate.Mapping.Attributes on 2007-02-09 20:20:39Z.-->
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  <class name="permissions.User, App_Code.ubtdkwky" table="br_user">
    <id type="Int64">
      <generator class="native" />
    </id>
    <property name="Id" />
    <property name="Login" />
    <property name="Password" />
    <bag name="Groups" table="br_usergroup">
      <key column="userId" />
      <many-to-many class="permissions.Group, App_Code.ubtdkwky" column="groupId" />
    </bag>
  </class>
</hibernate-mapping>


Mapping for Group:
Code:
<?xml version="1.0" encoding="utf-8"?>
<!--Generated by NHibernate.Mapping.Attributes on 2007-02-09 20:20:39Z.-->
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  <class name="permissions.Group, App_Code.ubtdkwky" table="br_group">
    <id type="Int64">
      <generator class="native" />
    </id>
    <property name="Name" />
    <property name="Id" />
    <many-to-one name="ParentGroup" column="parentGroupId" cascade="save-update" />
    <bag name="ChildGroups" lazy="true" cascade="save-update" inverse="true">
      <key column="parentGroupId" />
      <one-to-many class="permissions.Group, App_Code.ubtdkwky" />
    </bag>
    <bag name="Users" table="br_usergroup" inverse="true">
      <key column="groupId" />
      <many-to-many class="permissions.User, App_Code.ubtdkwky" column="userId" />
    </bag>
  </class>
</hibernate-mapping>



Full stack trace of any exception that occurs:
None.

Name and version of the database you are using:
MySQL 5.0.27-community-nt


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 14, 2007 7:14 pm 
Newbie

Joined: Fri Feb 09, 2007 3:24 pm
Posts: 3
To add, this is the output of NHibernate (DEBUG Level):

Code:
00:11:26.671 [6596] DEBUG NHibernate.Impl.SessionImpl - saving [permissions.Group#<null>]
00:11:26.687 [6596] DEBUG NHibernate.Impl.SessionImpl - executing insertions
00:11:26.687 [6596] DEBUG NHibernate.Engine.Cascades - processing cascades for: permissions.Group
00:11:26.687 [6596] DEBUG NHibernate.Engine.Cascades - cascading to SaveOrUpdate()
00:11:26.687 [6596] DEBUG NHibernate.Impl.SessionImpl - SaveOrUpdate() persistent instance
00:11:26.687 [6596] DEBUG NHibernate.Engine.Cascades - done processing cascades for: permissions.Group
00:11:26.687 [6596] DEBUG NHibernate.Impl.WrapVisitor - Wrapped collection in role: permissions.Group.ChildGroups
00:11:26.687 [6596] DEBUG NHibernate.Impl.WrapVisitor - Wrapped collection in role: permissions.Group.Users
00:11:26.687 [6596] DEBUG NHibernate.Persister.EntityPersister - Inserting entity: permissions.Group (native id)
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Opened new IDbCommand, open IDbCommands :1
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Building an IDbCommand object for the SqlString: INSERT INTO br_group (Name, parentGroupId, Id) VALUES (:Name, :parentGroupId, :Id)
00:11:26.687 [6596] DEBUG NHibernate.Persister.EntityPersister - Dehydrating entity: [permissions.Group#<null>]
00:11:26.687 [6596] DEBUG NHibernate.Type.StringType - binding 'Ubergods' to parameter: 0
00:11:26.687 [6596] DEBUG NHibernate.Type.Int64Type - binding '1' to parameter: 1
00:11:26.687 [6596] DEBUG NHibernate.Type.Int64Type - binding '0' to parameter: 2
00:11:26.687 [6596] DEBUG NHibernate.SQL - INSERT INTO br_group (Name, parentGroupId, Id) VALUES (?p0, ?p1, ?p2)
00:11:26.687 [6596] DEBUG NHibernate.SQL - ?p0 = 'Ubergods'
00:11:26.687 [6596] DEBUG NHibernate.SQL - ?p1 = '1'
00:11:26.687 [6596] DEBUG NHibernate.SQL - ?p2 = '0'
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Closed IDbCommand, open IDbCommands :0
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Opened new IDbCommand, open IDbCommands :1
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Building an IDbCommand object for the SqlString: SELECT LAST_INSERT_ID()
00:11:26.687 [6596] DEBUG NHibernate.SQL - SELECT LAST_INSERT_ID()
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Opened Reader, open Readers :1
00:11:26.687 [6596] DEBUG NHibernate.Persister.AbstractEntityPersister - Natively generated identity: 2
00:11:26.687 [6596] DEBUG NHibernate.Driver.NHybridDataReader - running NHybridDataReader.Dispose()
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Closed Reader, open Readers :0
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Closed IDbCommand, open IDbCommands :0
00:11:26.687 [6596] DEBUG NHibernate.Engine.Cascades - processing cascades for: permissions.Group
00:11:26.687 [6596] DEBUG NHibernate.Engine.Cascades - cascading to collection: permissions.Group.ChildGroups
00:11:26.687 [6596] DEBUG NHibernate.Engine.Cascades - done processing cascades for: permissions.Group
00:11:26.687 [6596] DEBUG NHibernate.Impl.SessionImpl - SaveOrUpdate() unsaved instance
00:11:26.687 [6596] DEBUG NHibernate.Impl.SessionImpl - saving [permissions.User#<null>]
00:11:26.687 [6596] DEBUG NHibernate.Impl.SessionImpl - executing insertions
00:11:26.687 [6596] DEBUG NHibernate.Impl.WrapVisitor - Wrapped collection in role: permissions.User.Groups
00:11:26.687 [6596] DEBUG NHibernate.Persister.EntityPersister - Inserting entity: permissions.User (native id)
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Opened new IDbCommand, open IDbCommands :1
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Building an IDbCommand object for the SqlString: INSERT INTO br_user (Login, Id, Password) VALUES (:Login, :Id, :Password)
00:11:26.687 [6596] DEBUG NHibernate.Persister.EntityPersister - Dehydrating entity: [permissions.User#<null>]
00:11:26.687 [6596] DEBUG NHibernate.Type.StringType - binding 'kork' to parameter: 0
00:11:26.687 [6596] DEBUG NHibernate.Type.Int64Type - binding '0' to parameter: 1
00:11:26.687 [6596] DEBUG NHibernate.Type.StringType - binding 'blah' to parameter: 2
00:11:26.687 [6596] DEBUG NHibernate.SQL - INSERT INTO br_user (Login, Id, Password) VALUES (?p0, ?p1, ?p2)
00:11:26.687 [6596] DEBUG NHibernate.SQL - ?p0 = 'kork'
00:11:26.687 [6596] DEBUG NHibernate.SQL - ?p1 = '0'
00:11:26.687 [6596] DEBUG NHibernate.SQL - ?p2 = 'blah'
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Closed IDbCommand, open IDbCommands :0
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Opened new IDbCommand, open IDbCommands :1
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Building an IDbCommand object for the SqlString: SELECT LAST_INSERT_ID()
00:11:26.687 [6596] DEBUG NHibernate.SQL - SELECT LAST_INSERT_ID()
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Opened Reader, open Readers :1
00:11:26.687 [6596] DEBUG NHibernate.Persister.AbstractEntityPersister - Natively generated identity: 1
00:11:26.687 [6596] DEBUG NHibernate.Driver.NHybridDataReader - running NHybridDataReader.Dispose()
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Closed Reader, open Readers :0
00:11:26.687 [6596] DEBUG NHibernate.Impl.BatcherImpl - Closed IDbCommand, open IDbCommands :0
00:11:26.687 [6596] DEBUG NHibernate.Impl.SessionImpl - closing session
00:11:26.687 [6596] DEBUG NHibernate.Impl.SessionImpl - disconnecting session
00:11:26.687 [6596] DEBUG NHibernate.Connection.ConnectionProvider - Closing connection
00:11:26.687 [6596] DEBUG NHibernate.Impl.SessionImpl - transaction completion


For some odd reasons, the collections are wrapped with Hibernates persistent collections, but no SQL is issued. I am somewhat out of ideas, so any help would be greatly appreciated.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 14, 2007 7:26 pm 
Newbie

Joined: Wed Feb 14, 2007 6:24 pm
Posts: 5
Kork,

You might want to try adding the cascade="save-update" attribute on your <bag>.

FYI, I've been poking around the documentation and many-to-many relationships are discouraged. From "best practices":

Quote:
Good usecases for a real many-to-many associations are rare. Most of the time you need additional information stored in the "link table". In this case, it is much better to use two one-to-many associations to an intermediate link class. In fact, we think that most associations are one-to-many and many-to-one, you should be careful when using any other association style and ask yourself if it is really neccessary.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 15, 2007 5:35 am 
Newbie

Joined: Fri Feb 09, 2007 3:24 pm
Posts: 3
Hi TimVasil,

thank you for the reply. I tried cascade SaveUpdate, didnt change a thing. While i get your point about the many-to-many, seeing that they are discouraged, i still think they should work, if hibernate offers them. Anyways, since i am somewhat out of ideas and i need some progress, i will convert this to a ternary relation and use many-to-one instead - hoping that this will help.

Best regards,
Kork


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 10, 2007 12:06 pm 
Beginner
Beginner

Joined: Thu Apr 19, 2007 5:37 am
Posts: 28
Kork wrote:
Hi TimVasil,

thank you for the reply. I tried cascade SaveUpdate, didnt change a thing. While i get your point about the many-to-many, seeing that they are discouraged, i still think they should work, if hibernate offers them. Anyways, since i am somewhat out of ideas and i need some progress, i will convert this to a ternary relation and use many-to-one instead - hoping that this will help.

Best regards,
Kork


I have the same issue with my many-to-many mapping.
The file is parsed correctly and the, no SQL appear in the debug logs...

I am clueless...

Any help ??


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 11, 2007 2:11 pm 
Beginner
Beginner

Joined: Thu Apr 19, 2007 5:37 am
Posts: 28
I am having this issue for 5 days now, I really can't find the solution.
Everything seems to work just fine, but no SQL is executed at all for the many-to-many relationship.
The rest of the classes are persisted without any problem...

PLEASE HELP :'(


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 12, 2007 9:12 am 
Newbie

Joined: Thu Jul 12, 2007 9:09 am
Posts: 7
I also have the same problem. I found that if you flush the session after saving, the link table is populated correctly. I have tried several cascade styles, and none of them appear to save the link table information automatically.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 12, 2007 9:25 am 
Beginner
Beginner

Joined: Thu Apr 19, 2007 5:37 am
Posts: 28
johnnyleitrim wrote:
I also have the same problem. I found that if you flush the session after saving, the link table is populated correctly. I have tried several cascade styles, and none of them appear to save the link table information automatically.


I would be interested in knowing how you get the flush to work, because in my case, even flush()ing don't make the relationship persistent :-(

I couldn't find any related bug in JIRA nor any related information in the docs nor the Hibernate book...

:( :(


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 12, 2007 10:01 am 
Regular
Regular

Joined: Mon Mar 20, 2006 10:49 pm
Posts: 59
Try setting inverse="false" on the Users and Groups bags.

_________________
Mike Abraham


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 12, 2007 10:15 am 
Beginner
Beginner

Joined: Thu Apr 19, 2007 5:37 am
Posts: 28
mabraham wrote:
Try setting inverse="false" on the Users and Groups bags.


I had it, just tested with both true and false, doesn't make any difference...
Is there a hot-line to call? ;-)

Honestly, I am afraid we might be hit by a bug?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 12, 2007 10:45 am 
Newbie

Joined: Thu Jul 12, 2007 9:09 am
Posts: 7
Strangely, I wrote a very small test program to show the error, but it works!!

Code:
public class Role {
   private Long id;

   private String name;

   public Long getId() {
      return id;
   }

   public void setId(Long id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }
}

Code:
import java.util.Set;

public class User {

   private Long id;

   private String name;

   private Set<Role> roles;

   public Long getId() {
      return id;
   }

   public void setId(Long id) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public Set<Role> getRoles() {
      return roles;
   }

   public void setRoles(Set<Role> roles) {
      this.roles = roles;
   }
}
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>
   <class name="Role" table="ROLE">
      <id name="id" column="ID">
         <generator class="native"/>
      </id>
      <property name="name" not-null="true"/>
   </class>
</hibernate-mapping>
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>
   <class name="User" table="USER">
      <id name="id" column="ID">
         <generator class="native"/>
      </id>
      <property name="name" not-null="true"/>
      <set name="roles" table="USER_ROLES">
         <key column="USER_ID"/>
         <many-to-many class="Role" column="ROLE_ID"/>
      </set>
   </class>
</hibernate-mapping>

Code:
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;

public class Test {
   public static void main(String[] args) {

      Properties properties = new Properties();

      properties.put(Environment.URL, "jdbc:hsqldb:mem:ManyToManyTest");
      properties.put(Environment.DRIVER, "org.hsqldb.jdbcDriver");
      properties.put(Environment.USER, "sa");
      properties.put(Environment.PASS, "");
      properties.put(Environment.POOL_SIZE, "1");
      properties.put(Environment.DIALECT, "org.hibernate.dialect.HSQLDialect");
      properties.put(Environment.CACHE_PROVIDER, "org.hibernate.cache.NoCacheProvider");
      properties.put(Environment.CURRENT_SESSION_CONTEXT_CLASS, "thread");
      properties.put(Environment.TRANSACTION_STRATEGY, "org.hibernate.transaction.JDBCTransactionFactory");
      properties.put(Environment.HBM2DDL_AUTO, "create");
      properties.put(Environment.SHOW_SQL, "true");

      Configuration cfg = new Configuration();
      cfg.setProperties(properties);

      cfg.addClass(Role.class);
      cfg.addClass(User.class);

      SessionFactory sessionFactory = cfg.buildSessionFactory();
      Session session = sessionFactory.getCurrentSession();
      session.beginTransaction();

      Transaction tx = sessionFactory.getCurrentSession().beginTransaction();

      // First, lets create a few standard roles:
      int nRoles = 5;

      Set<Role> roles = new HashSet<Role>();

      for (int i = 0; i < nRoles; i++) {
         Role role = new Role();
         role.setName("Role" + i);
         session.save(role);
         roles.add(role);
      }

      // Lets create a user with these roles:
      User user = new User();
      user.setName("user");
      user.setRoles(roles);

      session.save(user);

      tx.commit();
   }
}



The output:

Quote:
Hibernate: insert into ROLE (name, ID) values (?, ?)
Hibernate: call identity()
Hibernate: insert into ROLE (name, ID) values (?, ?)
Hibernate: call identity()
Hibernate: insert into ROLE (name, ID) values (?, ?)
Hibernate: call identity()
Hibernate: insert into ROLE (name, ID) values (?, ?)
Hibernate: call identity()
Hibernate: insert into ROLE (name, ID) values (?, ?)
Hibernate: call identity()
Hibernate: insert into USER (name, ID) values (?, ?)
Hibernate: call identity()
Hibernate: insert into USER_ROLES (USER_ID, ROLE_ID) values (?, ?)
Hibernate: insert into USER_ROLES (USER_ID, ROLE_ID) values (?, ?)
Hibernate: insert into USER_ROLES (USER_ID, ROLE_ID) values (?, ?)
Hibernate: insert into USER_ROLES (USER_ID, ROLE_ID) values (?, ?)
Hibernate: insert into USER_ROLES (USER_ID, ROLE_ID) values (?, ?)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 12, 2007 10:53 am 
Newbie

Joined: Thu Jul 12, 2007 9:09 am
Posts: 7
Did some more investigation. As in my previous mails, it looks like it doesn't insert the link table values until the session if flushed/closed.

I modified the code above to include a search:

Code:
      for (int i = 0; i < nRoles; i++) {
         Role role = new Role();
         role.setName("Role" + i);
         session.save(role);
         roles.add(role);
      }

      // Lets create a user with these roles:
      User user = new User();
      user.setName("user");
      user.setRoles(roles);

      session.save(user);

      Criteria c = session.createCriteria(User.class).createCriteria("roles").add(Restrictions.eq("name", "Role1"));

      System.out.println("CRITERIA: " + c.list());

      tx.commit();


Criteria is empty, and the "SELECT" of the criteria comes *before* the inserts for the link table:

Quote:
Hibernate: insert into ROLE (name, ID) values (?, ?)
Hibernate: call identity()
Hibernate: insert into ROLE (name, ID) values (?, ?)
Hibernate: call identity()
Hibernate: insert into ROLE (name, ID) values (?, ?)
Hibernate: call identity()
Hibernate: insert into ROLE (name, ID) values (?, ?)
Hibernate: call identity()
Hibernate: insert into ROLE (name, ID) values (?, ?)
Hibernate: call identity()
Hibernate: insert into USER (name, ID) values (?, ?)
Hibernate: call identity()
Hibernate: select this_.ID as ID1_1_, this_.name as name1_1_, roles3_.USER_ID as USER1_, role1_.ID as ROLE2_, role1_.ID as ID0_0_, role1_.name as name0_0_ from USER this_ inner join USER_ROLES roles3_ on this_.ID=roles3_.USER_ID inner join ROLE role1_ on roles3_.ROLE_ID=role1_.ID where role1_.name=?
CRITERIA: []
Hibernate: insert into USER_ROLES (USER_ID, ROLE_ID) values (?, ?)
Hibernate: insert into USER_ROLES (USER_ID, ROLE_ID) values (?, ?)
Hibernate: insert into USER_ROLES (USER_ID, ROLE_ID) values (?, ?)
Hibernate: insert into USER_ROLES (USER_ID, ROLE_ID) values (?, ?)
Hibernate: insert into USER_ROLES (USER_ID, ROLE_ID) values (?, ?)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 12, 2007 11:21 am 
Beginner
Beginner

Joined: Thu Apr 19, 2007 5:37 am
Posts: 28
I get a select on my many-to-many relationship table but no inserts...

very weird. I am wondering what could be happening here


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 12, 2007 1:01 pm 
Expert
Expert

Joined: Fri May 13, 2005 11:13 am
Posts: 292
Location: Rochester, NY
Going back to the original post, I see two issues. First, use of SaveOrUpdate() requires <unsaved-value> to be set somewhere in the mappings, which it doesn't seem to be. Second, the unit of work should be wrapped in a transaction:

Code:
using ( ISession session = factory.openSession() )
using ( ITransaction tx = session.BeginTransaction() ) {
   session.SaveOrUpdate( p );
   session.SaveOrUpdate( q );
   session.SaveOrUpdate( user );
   tx.Commit();
}


pevjan, you never posted code, so I don't know if you have these problems. (I imagine Kork has given up on us long ago.) If so, does fixing them help? Or could you post your code and mappings?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 12, 2007 1:51 pm 
Beginner
Beginner

Joined: Thu Apr 19, 2007 5:37 am
Posts: 28
thank you, i will post code tomorrow from the office.
as far as I am concerned, I do have a transaction...

thanks!


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 25 posts ]  Go to page 1, 2  Next

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.