EJB 3.0 Persistence with Parent/Child and composite keys
jseriff Jan 3, 2008 5:09 PMI 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.
------------------ | PARENT | ------------------ | PARENT_ID (PK) | | <attributes> | ------------------ ------------------ | CHILD | ------------------ | PARENT_ID (PK) | | CHILD_ID (PK) | | <attributes> | ------------------
I also have entity classes for these two tables -
@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 -
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)-
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.0 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.
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