-->
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.  [ 3 posts ] 
Author Message
 Post subject: Parent/Child and composite keys using Annotations
PostPosted: Sat Jan 05, 2008 12:19 pm 
Newbie

Joined: Sat Jan 05, 2008 12:07 pm
Posts: 1
I previously posted this on the JBoss EJB3 forums, but I thought it might be more relevant to these forums:

I have a fairly common scenario which I am having trouble getting to work as I expect. I have searched through the documentation and forums, but have not yet found any information which helped be with my issue.

I have two tables, lets call them PARENT and CHILD in a MySQL database.

Code:
------------------
| PARENT         |
------------------
| PARENT_ID (PK) |
| <attributes>   |
------------------

------------------
| CHILD          |
------------------
| PARENT_ID (PK) |
| CHILD_ID (PK)  |
| <attributes>   |
------------------



I also have entity classes for these two tables, and the composite primary key -

Code:
@Entity
@Table(name="parent")
public class Parent implements Serializable {
    @Id
    @GeneratedValue
    @Column(name="parent_id")
    private int parentId;

    @OneToMany(cascade={CascadeType.ALL})
    @JoinColumn(name="parent_id")
    private List<Child> children;

    //getters,setters,etc.
}

@Entity
@Table(name="child")
public class Child implements Serializable {
   @EmbeddedId
   private ChildId childId;

   //getters, setters, hashCode, equals, etc
}

@Embeddable
public class ChildId implements Serializable {
    @Column(name="parent_id")
    private int parentId;

    @Column(name="child_id")
    private int childId;

    //getters, setters, hashCode, equals, etc.
}



So far, this seems pretty straight forward, and I believe gives me what I want.

If I create a new Parent object, add child objects and merge, it appears to save, although in a strange fashion. (Note: I am using merge, as in the general case, these may or may not be new objects).

The (paraphrased) SQL which is generated using hibernate is -

Code:
insert on PARENT.
insert on CHILD set PARENT_ID = 0 and CHILD_ID = <correct child_id>.
update on CHILD set PARENT_ID = <correct parent_id> and CHILD_ID = <correct child_id> where PARENT_ID = 0 and CHILD_ID = <correct child_id>


This does appear to get the job done, but I run into a major problem when I try to insert two parent_ids where child_id has the same value. For example, if I have a Parent1 with a Child1 and a Child2 and a Parent2 with a Child2 (different object, same CHILD_ID) and a Child3 I get the following statements (paraphrased)-

Code:
insert on PARENT.
insert on PARENT.
insert on CHILD set PARENT_ID = 0 and CHILD_ID = 1
insert on CHILD set PARENT_ID = 0 and CHILD_ID = 2
insert on CHILD set PARENT_ID = 0 and CHILD_ID = 2 (not sure why this doesn't fail... i believe its done via a batch insert?)
insert on CHILD set PARENT_ID = 0 and CHILD_ID = 3
update on CHILD set PARENT_ID = 1 where PARENT_ID = 0 and CHILD_ID = 1
update on CHILD set PARENT_ID = 1 where PARENT_ID = 0 and CHILD_ID = 2
update on CHILD set PARENT_ID = 2 where PARENT_ID = 0 and CHILD_ID = 2
update on CHILD set PARENT_ID = 2 where PARENT_ID = 0 and CHILD_ID = 3



It then throws an exception because the update expected to change one row, and it changed none (the third update statement has no effect).

I am using JBoss 4.2 and SEAM 2.0GA out of the box.

I am not clear what I am doing wrong. I assume that the insert with parent_id is 0 is because there is no parent_id set on the child object. I would also assume that the persistence manager would be responsible for setting this after the parent objects are inserted. Do I need to merge() the parent with no children, and then add the children and re-merge?

I would prefer not to have a backwards reference from the child object back to the parent object, as this seems redundant, and will never be used in this context. Am I missing an annotation, or annotation parameter somewhere which will get me the expected behavior? (I would expect to see only 2 parent and 4 child inserts, with no updates at all). Am I forced to flush the persistence manager between each merge(parent) call?

Thanks for your help,
Jason


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 01, 2008 10:12 am 
Beginner
Beginner

Joined: Tue Jan 08, 2008 2:15 pm
Posts: 22
I had the same problem. My understanding is that because you have a unidirectional association and the FK key is in the child table (of course) and you are not using an association table, HB inserts into the parent table, then inserts into the child table with a null/0 (depending of mapping settings I guess) and then update the FK in the child with the parent.

I have solved the extra update with a bidirectional association in which the child is the owener of the relation, but I still have problems with the ID of the parent. I don't know how to tell HB to use the parent Id to perfom the insert into the child automatically, so I cannot use any cascading stuff.

Let me know if you find your way through that one. I have been searching for an HB solution for many hours now and could not find help in the HB book, documentation or forum!


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 01, 2008 10:27 am 
Beginner
Beginner

Joined: Tue Jan 08, 2008 2:15 pm
Posts: 22
Well, futhermore I had to mark the ManyToOne association in the child as insertable=false, updatable=false since the column was already mapped as part of the PK of the child table.

BUt the parent Id sharing with its child for their own composite PK was not solved at all. HB would let the FK reference to null in the child since the ManyToOne association in the child was insertable=false, updatable=false.

I used @IdClass and I tried to set insertable=false, updatable=false on the PK segment referring to the parent table instead of the ManyToOne association in the child, but HB seems to ignore insertable=false, updatable=false on "id" fields (can some one confirm that by pointing to documentation somewhere?).

Finallly, it seems I have solved the parent id problem by changing the getParentId() in the child to set the parentId field in the child to the one of the parent by exploiting the link I have to the parent from the child entity. HB inserts into the parent, sets the Id field in the parent, then when getting the PK segment pointing to the parent, I assign it from the parent ManyToOne link in the child just before returning it so HB can reuse it.


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