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