-->
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.  [ 12 posts ] 
Author Message
 Post subject: How to best map common Parent/Child relationship?
PostPosted: Tue May 09, 2006 1:12 pm 
Beginner
Beginner

Joined: Mon Aug 15, 2005 9:00 pm
Posts: 37
Hi,

In my legacy DB, we often have a parent table which has a PK from a sequnce. Then parent has one or more child tables which uses parent PK as not null FK to form composite key for child tables.

From application side, Presentation tier would like to build up Parent/Child object graph and pass to server DAO in one request. and DAO should ideally persist the graph in one shot. Please note the Child class is entired "contained" within the Parent class, i.e. Child class's life-cycle is bound by the Parent class and any access to Child class must go thru the Parent class.

So far I have experimented with bidirectional and unidirectional one-to-many mapping without success. The problem is that the when Presentation tier constuct the child composite id class. It does not know what's the parent id (not obtained until DAO ask DB), so it leave it as NULL. When DAO persists the Child class with NULL parent id in its composite key, DB throws constraint violation exception.

The following is my bidrectional mapping and sample Java code. I wonder what's the best practice people have found for this common problem - I prefer changing the mapping file while still leave the Presentation tier to build the object graph:

// DB DDL

CREATE TABLE Parent (
parentId INTEGER NOT NULL
);

ALTER TABLE Parent
ADD ( PRIMARY KEY (parentId) ) ;



CREATE TABLE Child (
parentId INTEGER NOT NULL,
childNumber INTEGER NOT NULL
);

ALTER TABLE Child
ADD ( PRIMARY KEY (parentId, childNumber) ) ;


// hibernate mapping

<class name="Parent" table="PARENT">
<id name="parentid" type="long">
<column name="PARENTID" precision="22" scale="0" />
<generator class="sequence">
<param name="sequence">seq_parentId</param>
</generator>
</id>
<set name="childs" inverse="true" cascade="all-delete-orphan">
<key>
<column name="PARENTID" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="Child" />
</set>
</class>

<class name="Child" table="CHILD">
<composite-id name="id" class="ChildId">
<key-property name="parentid" type="long">
<column name="PARENTID" precision="22" scale="0" />
</key-property>
<key-property name="childnumber" type="long">
<column name="CHILDNUMBER" precision="22" scale="0" />
</key-property>
</composite-id>
<many-to-one name="parent" class="Parent" update="false" insert="false" fetch="select">
<column name="PARENTID" precision="22" scale="0" not-null="true" />
</many-to-one>
</class>


// simplified Java code:

Parent p = new Parent();
Child c = new Child();
c.setParent(p);
ChildId cid = new ChildId();
cid.setChildnumber(101);
//cid.setParentid(1); // this is unreasoable to Pres
c.setId(cid);
p.getChilds().add(c);

// DAO tier
Session ssn = sessionFactory.openSession();
Transaction tx = ssn.beginTransaction();
Serializable s;
s = ssn.save(p);

tx.commit();
ssn.close();


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 09, 2006 1:19 pm 
Regular
Regular

Joined: Mon Aug 22, 2005 1:11 pm
Posts: 50
Location: Pasadena, CA
you need to use subclass in your child class.


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 09, 2006 4:00 pm 
Beginner
Beginner

Joined: Mon Aug 15, 2005 9:00 pm
Posts: 37
why subclass - I think that is only used for inheritance. Parent and Child class are not in any inheritance (or interface/implementation ) relationship


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 09, 2006 4:04 pm 
Regular
Regular

Joined: Mon Aug 22, 2005 1:11 pm
Posts: 50
Location: Pasadena, CA
I was taking parent and child to mean inheritence. You just mean to say that one class has another class as a property?


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 10, 2006 1:19 pm 
Beginner
Beginner

Joined: Mon Aug 15, 2005 9:00 pm
Posts: 37
yes. child is contained by parent as a property (collection). child does not inherit from parent. e.g. Address is contained by Person.


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 10, 2006 1:34 pm 
Regular
Regular

Joined: Mon Aug 22, 2005 1:11 pm
Posts: 50
Location: Pasadena, CA
Ok.

Either the child or the parent has to allow for a null identifier reference. You then presist that one first. then Persist the other. Finall go back and update the first which will give it the correct reference to the second.


Top
 Profile  
 
 Post subject:
PostPosted: Wed May 10, 2006 3:22 pm 
Newbie

Joined: Thu May 04, 2006 1:11 pm
Posts: 12
Hi chuckzhg,
Look at post http://forum.hibernate.org/viewtopic.ph ... 23#2304716 , I think it can help, if you don't have to handle with database errors (that is the problem that I am trying to solve...)
If you find any correction to this example, please tell me.


Top
 Profile  
 
 Post subject: Q: map Person has collection of Address (with composite key)
PostPosted: Thu May 11, 2006 2:01 am 
Beginner
Beginner

Joined: Mon Aug 15, 2005 9:00 pm
Posts: 37
Thx for the reply, panisson. My Person/Address example is somewhat different from yours

If the Child class has its on ID column based on DB sequence, Hibernate has no problem in creating the object graph in one go using regular bidrectional one-to-many mapping.

But my legacy DB's Child class has a composite key:

Code:
CREATE TABLE Child (
       parentId             INTEGER NOT NULL,
       childNumber          INTEGER NOT NULL
);


ALTER TABLE Child
       ADD  ( PRIMARY KEY (parentId, childNumber) ) ;

CREATE TABLE Parent (
       parentId             INTEGER NOT NULL
);


ALTER TABLE Parent
       ADD  ( PRIMARY KEY (parentId) ) ;


and my mapping is:
Code:
    <class name="Parent" table="PARENT">
        <id name="parentid" type="long">
            <generator class="sequence">
                <param name="sequence">seq_parentId</param>
            </generator>
        </id>
        <set name="childs" inverse="true" cascade="all-delete-orphan">
            <key column="PARENTID" not-null="true" />
            <one-to-many class="Child" />
        </set>
    </class>

    <class name="Child" table="CHILD">
        <composite-id name="id" class="ChildId">
            <key-property name="parentid" type="long" />
            <key-property name="childnumber" type="long" />
        </composite-id>
        <many-to-one name="parent" class="Parent" update="false" insert="false" fetch="select" />
    </class>


But when I run the following code:

Code:
       
        // Pres tier construct obj graph
        Parent p = new Parent();
        Child c = new Child();
        c.setParent(p);
        ChildId cid = new ChildId(); // needs parentId and childNumber
        cid.setChildnumber(101);
        //don't know what to put for ChildId.parentId, so it's NULL
        c.setId(cid);
        p.getChilds().add(c);
       
        // DAO tier
        Session ssn = sessionFactory.openSession();
        Transaction tx = ssn.beginTransaction();
        Serializable s;
        s = ssn.save(p);
       
        tx.commit();
        ssn.close();


I got exception on NULL ChildId.parentId:

Code:
Hibernate: /* insert Parent */ insert into SCOTT.PARENT (PARENTID) values (?)
Hibernate: /* insert Child */ insert into SCOTT.CHILD (PARENTID, CHILDNUMBER) values (?, ?)
Exception in thread "main" org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
...
Caused by: java.sql.BatchUpdateException: ORA-02291: integrity constraint (SCOTT.SYS_C002917) violated - parent key not found


How can Hibernate handle this common use case gracefully?


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 11, 2006 9:13 am 
Newbie

Joined: Thu May 04, 2006 1:11 pm
Posts: 12
Maybe the best approach is to include the many-to-one in the composite-id:

Code:
   <class name="test.domain.Parent" table="PARENT">
        <id name="parentid" type="long">
            <generator class="sequence">
                <param name="sequence">seq_parentId</param>
            </generator>
        </id>
        <set name="childs" inverse="true" cascade="all-delete-orphan">
            <key column="PARENTID" not-null="true" />
            <one-to-many class="test.domain.Child" />
        </set>
    </class>

    <class name="test.domain.Child" table="CHILD">
        <composite-id name="id" class="test.domain.ChildId">
            <key-many-to-one name="parent" class="test.domain.Parent" column="parentid"/>
            <key-property name="childnumber"/>
        </composite-id>
    </class>


and include the Parent in the ChildId:

Code:
           // Pres tier construct obj graph
           Parent p = new Parent();
           Child c = new Child();
           ChildId cid = new ChildId(); // needs parent and childNumber
           cid.setParent(p);
           cid.setChildnumber(101);
           c.setId(cid);
           p.getChilds().add(c);
          
           // DAO tier
           Session ssn = sessionFactory.openSession(conn);
           Transaction tx = ssn.beginTransaction();
           Serializable s;
           s = ssn.save(p);
          
           tx.commit();
           ssn.close();


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 11, 2006 1:07 pm 
Newbie

Joined: Tue Jul 20, 2004 1:25 pm
Posts: 12
Try using a foreign generator strategy to populate the child's FK value

-- snippet from Hibernate reference (5.1.11)
Code:
<class name="person" table="PERSON">
<id name="id" column="PERSON_ID">
<generator class="foreign">
<param name="property">employee</param>
</generator>
</id>
...
<one-to-one name="employee"
class="Employee"
constrained="true"/>
</class>


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 12, 2006 8:50 pm 
Beginner
Beginner

Joined: Mon Aug 15, 2005 9:00 pm
Posts: 37
Thanks a lot panisson.

So it seems for hibernate to handle composite-id composed of foreign key, the only working solution is using <key-many-to-one> and have the ChildId class hold a reference to the Parent class


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 19, 2006 2:40 am 
Beginner
Beginner

Joined: Mon Aug 15, 2005 9:00 pm
Posts: 37
Discussed with Gavin King in JavaOne today about this issue. He does not recomend <key-many-to-one> (I did not ask why). He recommend Parent id uses generator="assigned" and it's up to application to get the id (from DB sequence or whereever) and set into both parent and child keys. I am wondering do I really want my pres tier to get next value from DB sequence? Opinions, anyone?


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