-->
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 with extra columns in join table
PostPosted: Tue Sep 02, 2003 2:46 pm 
Regular
Regular

Joined: Tue Aug 26, 2003 7:53 pm
Posts: 66
Location: Lakeland, Florida USA
[yes, I'm still working on this.]

1) Mapping a many-to-many with Set & composite-element as specified in sec 6.2. See hbm below.

2) In order to implement equals & .hashcode in the the composite-element class (AdAUserRoleXref), don't I have to use the parent element tag within the composite-element? Otherwise, adAUseridMain is always null. Without the equals & .hashcode methods, hibernate deletes the entire collection and re-adds everyone again, plus the new item.

3) I get an extra composite-element in the collection on the load AdAUseridMain that is not in the db. The extra item does not have a AdAUseridMain (its null) so this causes a npe in AdAUseridMain.hashcode. This extra item does have a role.

4) Christian Bauer's reply on the old forum was to
Quote:
Make sure that your component properties are all "not null" if you're using a Set for the the collection.

Does this mean,

<property not-null="true" column="CREATE_DATE" name="createDate" type="java.sql.Timestamp" />

Did that but didn't help. Christian must mean something else?

Thanks,

Jeff Boring

Code:

console messages:

INFO: Hibernate 2.1 beta 1
...
Hibernate: select adauseri0_.SKEY as SKEY0_, adauseri0_.MANAGER_ID as MANAGER_ID0_, adauseri0_.USERID as USERID0_, adauseri0_.PWD as PWD0_, adauseri0_.LNAME as LNAME0_, adauseri0_.M_INIT as M_INIT0_, adauseri0_.FNAME as FNAME0_, adauseri0_.NOTES_ADDRESS as NOTES_AD8_0_, adauseri0_.TITLE as TITLE0_, adauseri0_.PHONE as PHONE0_, adauseri0_.MC as MC0_, adauseri0_.BUDGET as BUDGET0_, adauseri0_.LOCATION as LOCATION0_, adauseri0_.DEPARTMENT as DEPARTMENT0_, adauseri0_.DIVISION as DIVISION0_, adauseri0_.SITE as SITE0_, adauseri0_.BUSINESS_UNIT as BUSINES17_0_, adauseri0_.BUYER_CODE as BUYER_CODE0_, adauseri0_.ACT_STAT_CD as ACT_STA19_0_, adauseri0_.LST_LOGIN_DATE as LST_LOG20_0_, adauseri0_.LST_UPD_DATE as LST_UPD21_0_, adauseri0_.LST_UPD_USERID as LST_UPD22_0_, adauseri0_.BU_GRP_CD as BU_GRP_CD0_, adauseri0_.OUT_OF_OFFICE_IND as OUT_OF_24_0_, adauseri0_.OUT_OF_OFFICE_TEXT as OUT_OF_25_0_, adauseri0_.EMAIL_ADDRESS as EMAIL_A26_0_, adauseri0_.PAGER_PHONE as PAGER_P27_0_, adauseri0_.PAGER_PIN as PAGER_PIN0_, adauseri0_.HOME_PHONE as HOME_PHONE0_, adauseri0_.FAX_PHONE as FAX_PHONE0_, adauseri0_.CELL_PHONE as CELL_PHONE0_, adauseri0_.LOCATION_CD as LOCATIO32_0_, adauseri0_.BAY_LOC as BAY_LOC0_, adauseri0_.CUBE_NUM as CUBE_NUM0_, adauseri0_.EMPLOYEE_TYPE as EMPLOYE35_0_, adauseri0_.ORG_CD as ORG_CD0_, adauseri0_.ORG_LVL as ORG_LVL0_, adauseri0_.USER_TYPE_CD as USER_TY38_0_, adauseri0_.INTRA_EXTRA_CD as INTRA_E39_0_, adauseri0_.PROFILE_SKEY as PROFILE40_0_, adauseri0_.ADDRESS_SKEY as ADDRESS41_0_ from tgaddba3.AD_A_USERID_MAIN adauseri0_ where adauseri0_.SKEY=?

Hibernate: select ad_a_use0_.CREATE_DATE as CREATE_D2___, ad_a_use0_.CREATE_USERID as CREATE_U3___, ad_a_use0_.LST_UPD_DATE as LST_UPD_4___, ad_a_use0_.LST_UPD_USERID as LST_UPD_5___, ad_a_use0_.ROLE_SKEY as ROLE_SKEY__, ad_a_use0_.USER_SKEY as USER_SKEY__, adrrole1_.ROLE_SKEY as ROLE_SKEY0_, adrrole1_.APPLICATION_ID as APPLICAT2_0_, adrrole1_.ROLE_CATEGORY as ROLE_CAT3_0_, adrrole1_.ROLE_DESC as ROLE_DESC0_, adrrole1_.ROLE_SORT_SEQ as ROLE_SOR5_0_, adrrole1_.ACTIVE_IND as ACTIVE_IND0_, adrrole1_.CREATE_DATE as CREATE_D7_0_, adrrole1_.CREATE_USERID as CREATE_U8_0_, adrrole1_.LST_UPD_DATE as LST_UPD_9_0_, adrrole1_.LST_UPD_USERID as LST_UPD10_0_ from tgaddba3.AD_A_USER_ROLE_XREF ad_a_use0_, tgaddba3.AD_R_ROLE adrrole1_ where ad_a_use0_.USER_SKEY=? and ad_a_use0_.ROLE_SKEY=adrrole1_.ROLE_SKEY(+)

java.lang.NullPointerException
   at com.siemens.pg.pma.vo.bp.AdAUserRoleXref.hashCode(AdAUserRoleXref.java:90)

<test-code>
   AdAUserRoleXref xref = null;
   AdRRole role = null; Set s = null; Iterator it = null;
   Session sess = DatastoreHBN.singleton().getSession();
   Transaction xac = sess.beginTransaction();
   GregorianCalendar today = new GregorianCalendar();
      
   try {
      AdAUseridMain u = (AdAUseridMain) sess.load( com.siemens.pg.pma.vo.bp.AdAUseridMain.class, new Integer(1125) );
      role = (AdRRole) sess.load( com.siemens.pg.pma.vo.bp.AdRRole.class, new Integer(201) );
      xref = new AdAUserRoleXref();
      xref.setCreateUserid( u.getUserid() );
      xref.setLstUpdUserid( u.getUserid() );
      xref.setCreateDate( today.getTime() );
      xref.setLstUpdDate( today.getTime() );
      xref.setAdAUseridMain( u );
      xref.setAdRRole( role );
      s = u.getAdRRoles();
      s.add( xref );
      sess.flush();
   }
   catch (Exception e ){
      e.printStackTrace();
   }
   finally {
      xac.commit();
      sess.close();
   }
</test-code>            
<hibernate-mapping>

<class name="com.siemens.pg.pma.vo.bp.AdAUseridMain" table="AD_A_USERID_MAIN" >
    <id name="skey" type="java.lang.Integer" column="SKEY" unsaved-value="any" >
        <generator class="assigned" />
    </id>
    <property name="managerId" type="java.lang.Integer" column="MANAGER_ID" length="9"    />
    <property name="userid" type="java.lang.String" column="USERID" not-null="true" length="8"    />
   ...

    <!-- bi-directional many-to-many association to AdRRole -->
    <set name="adRRoles" lazy="false" table="AD_A_USER_ROLE_XREF" cascade="all" >
        <key column="USER_SKEY" />
        <composite-element class="com.siemens.pg.pma.vo.bp.AdAUserRoleXref" >
           <parent name="adAUseridMain" />
           <property not-null="true" column="CREATE_DATE" name="createDate" type="java.sql.Timestamp" />
           <property  not-null="true" column="CREATE_USERID" name="createUserid" type="java.lang.String" />
           <property  not-null="true" column="LST_UPD_DATE" name="lstUpdDate" type="java.sql.Timestamp" />
           <property  not-null="true" column="LST_UPD_USERID" name="lstUpdUserid" type="java.lang.String" />
           <many-to-one name="adRRole" class="com.siemens.pg.pma.vo.bp.AdRRole">
              <column name="ROLE_SKEY" />
           </many-to-one>
        </composite-element>
    </set>
</class>
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 02, 2003 6:36 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Quote:
don't I have to use the parent element tag within the composite-element?


Why would you include the parent? I can't think of any reason to. I would explicitly say not include it.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 02, 2003 7:22 pm 
Regular
Regular

Joined: Tue Aug 26, 2003 7:53 pm
Posts: 66
Location: Lakeland, Florida USA
Gavin, without the parent tag adAUseridMain was always null in the collection. With it, it contains the right values for the elements in the db but those mystery elements show up. Hum... this tells me something else is not right. I want to model it with Set because I believe that's the right way - no dup's. Perhaps I'll try map tomorrow.

Jeff


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 02, 2003 7:31 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
I don't understand what the mystery elements are, but you should not use the parent in an equals(). It makes no sense.


I'm pretty certain this works, by the way. If you can submit a Very Simple main() method to JIRA, I will take a quick look and see what is wrong.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 03, 2003 12:21 pm 
Regular
Regular

Joined: Tue Aug 26, 2003 7:53 pm
Posts: 66
Location: Lakeland, Florida USA
I have posted the issue.

Jeff


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 03, 2003 10:11 pm 
Regular
Regular

Joined: Wed Sep 03, 2003 9:56 pm
Posts: 58
Can someone please provide an example ternary mapping of tables A, B and C though the join table ABC.

I'm looking for something like this,

Code:
A--ABC--B
    |
    C


Any suggestions?

Thanks,
-Mitch

P.S. I have seen the example in the Reference Document and searched the forum, but still can't figureout the syntax.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 03, 2003 11:35 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Oh OK, I understand now:

The correct mapping is:

Code:
    <!-- bi-directional many-to-many association to Role -->
    <set name="roles" lazy="false" table="UserRole" cascade="all" >
        <key column="userskey" />
        <composite-element class="UserRole" >
           <parent name="user"/>
           <property  not-null="true" name="noteComment" type="java.lang.String" />
           <many-to-one name="role" class="Role">
              <column name="roleskey" />
           </many-to-one>
        </composite-element>
    </set>



And the correct implementation of equals()/hashCode() is:

Code:
   public boolean equals(Object other) {
      if ( !(other instanceof UserRole) ) return false;
      UserRole castOther = (UserRole) other;
         return new EqualsBuilder()
               .append(this.getRole().getRoleskey(), castOther.getRole().getRoleskey() )
               //.append(this.getUser().getUserskey(), castOther.getUser().getUserskey() )
               .isEquals();
   }

   public int hashCode() {
         return new HashCodeBuilder()
               .append( this.getRole().getRoleskey() )
               //.append( this.getUser().getUserskey() )
               .toHashCode();
   }



ie. don't include the <parent> property in the equals()/hashCode(). Just include the other properties.

NOTES:
=====
* Now, could maybe change Hibernate so that it supports use of the <parent> in the equals/hashCode. It actually the deepcopy we keep for dirty checking that gets the null reference. This is an easy fix.

* In playing with your code I found a little bug in Set where if we change a property that is NOT in the equals()/hashCode() (noteComment, in this case), we don't update the set properly. This is kinda rare in actual practical examples. And anyway it is a 4-character change to fix it. I have made the fix to both branches in CVS.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 04, 2003 12:04 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
OK, I have made the change suggested in the first note (in Hibernate 2.1 branch). This will allow you to use the user property in the equals/hashCode.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 04, 2003 1:59 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
OH, PPS.


Something I noticed in your code was unnecessary calls to Session.save().


Hibernate AUTOMAGICALLY detects changes to any instances associated with an open session. You do NOT need to call save() or update() to make Hibernate persist changes to objects it already knows about.


This feature is called "automatic dirty checking".


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 04, 2003 9:26 am 
Regular
Regular

Joined: Tue Aug 26, 2003 7:53 pm
Posts: 66
Location: Lakeland, Florida USA
> ie. don't include the <parent> property in the equals()/hashCode(). Just include the other properties. <

Yes, this does work. Why I didn't think of that I can't say. But, then again, doesn't hashCode have to be unique? Wouldn't 2 roles assigned to different users produce the same hashCode?

> change suggested in the first note (in Hibernate 2.1 branch). <

Couldn't find anything not at least 8 days old at http://cvs.sourceforge.net/cgi-bin/view ... =v21branch

> unnecessary calls to Session.save() <

right you are, in the 2nd transaction.

Thanks for the help!

Jeff


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 04, 2003 11:07 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
* hashCodes don't need to be unique
* view CVS is 24 hours behind at present


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.