-->
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.  [ 9 posts ] 
Author Message
 Post subject: Object with combination of 2 primary keys
PostPosted: Thu Apr 15, 2004 12:24 pm 
Senior
Senior

Joined: Wed Mar 24, 2004 11:40 am
Posts: 146
Location: Indianapolis, IN, USA
I am using Hibernate 2.1.2 with SAPDB 7.4.

The problem here is that I am unsure about terminology as it pertains to combination keys, surrogate keys etc. Here is the table structure I am dealing with.

I have an ORDERS table with Primary Key ORDERID and an ORDERLINEITEMS table with Primary Key of ORDERID and LINEITEMID.

Code:
TABLE ORDERS
  ORDERID INTEGER PK
  ...
  ...

TABLE ORDERLINEITEMS
  ORDERID INTEGER PK
  LINEITEMID INTEGER PK
  ...
  ...



The Order object has the ORDERID provided to it by a sequence with the following mapping. The mapping from the Order object to the LineItem object is a one-to-many relationship.

Code:
<hibernate-mapping>
  <class name="com.foo.bar.beans.order.Order" table="ORDERS" dynamic-update="false" dynamic-insert="false">
    <id name="orderId" column="ORDERID" type="java.lang.Long" unsaved-value="null">
      <generator class="sequence">
        <param name="sequence">SEQ_ORDERID</param>
      </generator>
    </id>
    ...
    ...
    <set name="assignedItemList" lazy="false" inverse="false" cascade="save-update" sort="unsorted" order-by="LINEITEMID">
      <key column="LINEITEMID"/>
      <one-to-many class="com.foo.bar.beans.order.LineItem"/>
    </set>
  </class>
</hibernate-mapping>


I think I sort of have a grasp on the situation till this point. But I am confused as to how I should map the LineItem object. I am assuming that the LineItem object will need an orderId attribute because of the nature of Hibernate as opposed to a regular OO structure where you need not have it if you are assigning the items to an Order object in a list. The cascade="save-update" from the Order object should tell Hibernate to save/update each individual line. But how does one go about mapping the LineItem object into LineItem.hbm.xml.

The object structure is as follows:

Code:
public class LineItem
  implements Serializable
{
  private Long orderId = null;
  private Long lineItemId = null;

  public Long getOrderId()
  {
    return orderId;
  }
  public void setOrderId(Long orderId)
  {
    this.orderId = orderId;
  }
  public Long getLineItemId()
  {
    return lineItemId;
  }
  public void setLineItemId()
  {
    this.lineItemId = lineItemId;
  }
  ...
  ...
}


I am using XDoclet to generate the config file. Any help is greatly appreciated.

TIA


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 15, 2004 2:02 pm 
Hibernate Team
Hibernate Team

Joined: Thu Dec 18, 2003 9:55 am
Posts: 1977
Location: France
you need a composite id with
- a key-many-to-one and a key property, if you need to navigate from lineOrder to order
- or 2 key-properties

if you want to generate this with xdoclet
just follow http://forum.hibernate.org/viewtopic.php?t=928795



Anthony


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 15, 2004 2:37 pm 
Senior
Senior

Joined: Wed Mar 24, 2004 11:40 am
Posts: 146
Location: Indianapolis, IN, USA
I must be completely missing the point but it seems like the example you suggested talks about an Object and its association with the generator class for its primary key. My first instinct was that the LineItem object would be mapped as something similar to this.


Code:
<hibernate-mapping>
  <class name="com.foo.bar.beans.order.LineItem" table="ORDERLINEITEMS" dynamic-update="true" dynamic-insert="true">
    <composite-id class="com.foo.bar.beans.order.Order">
      <key-property name="lineItemId" type="java.lang.Long">
      <key-many-to-one name="order" type="com.foo.bar.beans.order.Order" column="orderId"/>
    </composite-id>
    ...
    ...
  </class>
</hibernate-mapping>


However, I think there are a couple of issues with this.

    1. The composite-id is pointing to the Order class. I don't understand what this should be I guess.

    2. Using the many-to-one would mean that I would have to have the Order as an attribute of the LineItem object (bi-directional relationship) instead of having the orderId. If I do this I will need to lazy load the Order object so that it doesn't get populated in the LineItem as well as the object that holds it.



Am I even in the same ballpark?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 15, 2004 2:59 pm 
Hibernate Team
Hibernate Team

Joined: Thu Dec 18, 2003 9:55 am
Posts: 1977
Location: France
i gave you the link to the other post because generating composite od from xdoclet is not "intuitive"

if you don't need to navigate from lineOrder to order, that means that you don't need to declare the many to one associaiton so just use two key properties

<key-property name="lineItemId" type="java.lang.Long">
<key-property name="orderId" type="java.lang.Long">


don't forget to use a lineItemCompositeClass and to write equals & hashcode


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 15, 2004 3:20 pm 
Senior
Senior

Joined: Wed Mar 24, 2004 11:40 am
Posts: 146
Location: Indianapolis, IN, USA
Thank you for the link. You are right about composite id from xDoclet not being too intuitive.

So it seems like I need a LineItemCompositeClass in the composite-id element for the class attribute. Am I right? Also, does the hashCode() and equals() implementation need to be in the LineItemCompositeClass or in the LineItem object?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 15, 2004 3:25 pm 
Senior
Senior

Joined: Wed Mar 24, 2004 11:40 am
Posts: 146
Location: Indianapolis, IN, USA
There is a good reference on Equals and HashCode for anyone that has the same or similar questions.

http://www.hibernate.org/Documentation/EqualsAndHashCode


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 15, 2004 5:58 pm 
Senior
Senior

Joined: Wed Mar 24, 2004 11:40 am
Posts: 146
Location: Indianapolis, IN, USA
I tried to create a composite key object and got into an even bigger mess.

Code:
public class LineItem
     implements Serializable
{
  /**  The lineItemCompositeKey attribute of the LineItem bean */
  private LineItemCompositeKey lineItemCompositeKey = null;
  ...
  ...
  /**
   *  Gets the lineItemCompositeKey attribute of the LineItem object
   *
   * @return                                    The lineItemCompositeKey value
   * @hibernate.id                              generator-class="assigned"
   * @hibernate.collection-composite-element    class="com.brightpoint.alltel.beans.order.LineItemCompositeKey"
   * @hibernate.collection-key                  column="ORDERID"
   * @hibernate.collection-key                  column="LINEITEMID"
   */
  public LineItemCompositeKey getLineItemCompositeKey()
  {
    return lineItemCompositeKey;
  }

  public void setLineItemCompositeKey(LineItemCompositeKey lineItemCompositeKey)
  {
    this.lineItemCompositeKey =
  }
  ...
  ...
}

public class LineItemCompositeKey
     implements Serializable
{
  /**  The orderId attribute of the LineItemCompositeKey bean */
  private Long orderId = null;

  /**  The lineItemId attribute of the LineItemCompositeKey bean */
  private Long lineItemId = null;

  /**  The default construtor for the LineItemCompositeKey object. */
  public LineItemCompositeKey() { }
 
  /**
   *  Gets the orderId attribute of the LineItemCompositeKey object
   *
   * @return                The orderId value
   * @hibernate.property    column = "ORDERID" not-null = "true" type="java.lang.Long"
   *      insert="true" update="false"
   */
  public Long getOrderId()
  {
    return orderId;
  }

  /**
   *  Gets the lineItemId attribute of the LineItemCompositeKey object
   *
   * @return                The lineItemId value
   * @hibernate.property    column = "LINEITEMID" not-null = "true" type="java.lang.Long"
   *      insert="true" update="false"
   */
  public Long getLineItemId()
  {
    return lineItemId;
  }
}


When I do my hibernatedoclet generation with Ant, I get the following stack trace:

Code:
[hibernatedoclet] Apr 15, 2004 4:30:58 PM xdoclet.template.TemplateEngine invokeMethod
[hibernatedoclet] SEVERE: Invoking method failed: xdoclet.modules.hibernate.HibernateTagsHandler.ifHasCompositeId, line=107 of template file: jar:file:C:\Projects\altweb\lib\xdoclet\xdoclet-hibernate-module-1.2.jar!/xdoclet/modules/hibernate/resources/hibernate.xdt
[hibernatedoclet] java.lang.reflect.InvocationTargetException
[hibernatedoclet]    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[hibernatedoclet]    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[hibernatedoclet]    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[hibernatedoclet]    at java.lang.reflect.Method.invoke(Method.java:324)
[hibernatedoclet]    at xdoclet.template.TemplateEngine.invoke(TemplateEngine.java:635)
[hibernatedoclet]    at xdoclet.template.TemplateEngine.invokeMethod(TemplateEngine.java:561)
[hibernatedoclet]    at xdoclet.template.TemplateEngine.invokeBlockMethod(TemplateEngine.java:959)
[hibernatedoclet]    at xdoclet.template.TemplateEngine.handleBlockTag(TemplateEngine.java:926)
[hibernatedoclet]    at xdoclet.template.TemplateEngine.handleTag(TemplateEngine.java:466)
[hibernatedoclet]    at xdoclet.template.TemplateEngine.generate(TemplateEngine.java:347)
[hibernatedoclet]    at xdoclet.template.TemplateEngine.start(TemplateEngine.java:414)
[hibernatedoclet]    at xdoclet.TemplateSubTask.startEngine(TemplateSubTask.java:560)
[hibernatedoclet]    at xdoclet.TemplateSubTask.generateForClass(TemplateSubTask.java:767)
[hibernatedoclet]    at xdoclet.TemplateSubTask.startProcessPerClass(TemplateSubTask.java:667)
[hibernatedoclet]    at xdoclet.TemplateSubTask.startProcess(TemplateSubTask.java:594)
[hibernatedoclet]    at xdoclet.XmlSubTask.startProcess(XmlSubTask.java:198)
[hibernatedoclet]    at xdoclet.modules.hibernate.HibernateSubTask.execute(HibernateSubTask.java:123)
[hibernatedoclet]    at xdoclet.XDocletMain.start(XDocletMain.java:48)
[hibernatedoclet]    at xdoclet.DocletTask.start(DocletTask.java:464)
[hibernatedoclet]    at xjavadoc.ant.XJavadocTask.execute(XJavadocTask.java:110)
[hibernatedoclet]    at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:193)
[hibernatedoclet]    at org.apache.tools.ant.Task.perform(Task.java:341)
[hibernatedoclet]    at org.apache.tools.ant.Target.execute(Target.java:309)
[hibernatedoclet]    at org.apache.tools.ant.Target.performTasks(Target.java:336)
[hibernatedoclet]    at org.apache.tools.ant.Project.executeTarget(Project.java:1339)
[hibernatedoclet]    at org.apache.tools.ant.Project.executeTargets(Project.java:1255)
[hibernatedoclet]    at org.apache.tools.ant.Main.runBuild(Main.java:609)
[hibernatedoclet]    at org.apache.tools.ant.Main.start(Main.java:196)
[hibernatedoclet]    at org.apache.tools.ant.Main.main(Main.java:235)
[hibernatedoclet] Caused by: java.lang.NullPointerException
[hibernatedoclet]    at xdoclet.modules.hibernate.HibernateTagsHandler.hasCompositeId_Impl(HibernateTagsHandler.java:529)
[hibernatedoclet]    at xdoclet.modules.hibernate.HibernateTagsHandler.ifHasCompositeId(HibernateTagsHandler.java:140)
[hibernatedoclet]    ... 29 more



I do NOT have hashCode() or equals() implemented in any of my objects. Is this related and if so, should the hashCode() and equals() be implemented in the LineItem object or the LineItemCompositeKey object?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 15, 2004 6:14 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 7:19 pm
Posts: 2364
Location: Brisbane, Australia
Your persistent class must override equals() and hashCode() to implement composite identifier equality. It must also implement Serializable.
http://www.hibernate.org/hib_docs/reference/html/or-mapping.html#or-mapping-s1-4b
and
http://www.hibernate.org/hib_docs/reference/html/components.html#components-s2-3


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 15, 2004 6:35 pm 
Senior
Senior

Joined: Wed Mar 24, 2004 11:40 am
Posts: 146
Location: Indianapolis, IN, USA
David,

Thank you for your help. I added the following code to my LineItemCompositeKey object and it generated the proper mapping.


Code:
/**
   *  The boolean value to see if the object passed in matches the current object
   *
   * @param  object  object value for the method
   * @return         boolean value to determine if the object matches the current
   *      object
   */
  public boolean equals(Object object)
  {
    boolean match = false;
    if (object != null)
    {
      LineItemCompositeKey lineItemCompositeKey = (LineItemCompositeKey) object;
      if (lineItemCompositeKey.getOrderId().longValue() == this.orderId.longValue() && lineItemCompositeKey.getLineItemId().longValue() == this.lineItemId.longValue())
      {
        match = true;
      }
    }
    return match;
  }

  /**
   *  This method returns the hashCode value of the object
   *
   * @return    int hashCode value of the object
   */
  public int hashCode()
  {
    int hashValue = 7;
    hashValue = 11 + orderId.hashCode();
    hashValue = (11 * hashValue) + lineItemId.hashCode();
    return hashValue;
  }


Generated mapping for composite key

Code:
<composite-id name="lineItemCompositeKey" class="com.foo.bar.beans.order.LineItemCompositeKey">
  <key-property name="orderId" type="java.lang.Long" column="ORDERID"/>
  <key-property name="lineItemId" type="java.lang.Long" column="LINEITEMID"/>
</composite-id>


The only question I have is, do you think my hashCode() method is ok or would it cause issues for me in respect to Hibernate?


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