Hi Jonathan, The workaround for the problem that you are facing would be, Either you can have the cascade on one side of the relationship(usually on the owning side which is the Child in your case) Or you can set only set the owning side of the relationship in your test program (in your case child is the owning side and do not do parent.addchild(). Just do child.addParent())for now. This should work.
I will fix the problem and post the patch soon. Thanks Sandhya Turaga --- On Mon, 1/5/09, Jonatan Samoocha <[email protected]> wrote: From: Jonatan Samoocha <[email protected]> Subject: Re: Unexpected merge/cascade behavior To: [email protected] Date: Monday, January 5, 2009, 2:58 AM Hi Sandhya, I tried to run the test case on JPA2.0, but got the same result. Anyway, I seem to be bound to JPA1.0.0 due to project constraints. You mention "debugging the problem", does that mean the behavior displayed in this test case is incorrect? How can I assist in debugging? Do you know of any workaround? Thanks, Jonatan Sandhya Kishore wrote: > > Please ignore my previous email on this. I have reproduced the problem and > I am trying to debug it. If I do not understand what is going on I will > post the testcase. > > --- On Wed, 12/17/08, Jonatan Samoocha <[email protected]> wrote: > From: Jonatan Samoocha <[email protected]> > Subject: Unexpected merge/cascade behavior > To: [email protected] > Date: Wednesday, December 17, 2008, 7:22 AM > > Hi all, > > I'm quite new to (Open)JPA and am experiencing unexpected behavior of the > merge() operation. I'm dealing with a parent and child entity that are > defined as follows: > > //Parent: > @Entity > @Table(name="TEST_PARENT") > public class TestParent { > @Id > @Column(name="ID", nullable=false) > private String id = new String(); > > @Column(name="name") > private String name = new String(); > > @OneToMany(mappedBy="parent", fetch=FetchType.EAGER, > cascade={CascadeType.ALL}) > private Set<TestChild> children = new HashSet<TestChild>(); > > @Override > public boolean equals(Object other) { > if (other != null && other instanceof TestParent) { > return ((TestParent)other).getId().equals(this.id); > } > > return false; > } > > @Override > public int hashCode() { > return id.hashCode(); > } > > // skipping getters/setters > > public void addChild(TestChild c) { > this.children.add(c); > c.setParent(this); > } > } > > //Child: > @Entity > @Table(name="TEST_CHILD") > public class TestChild { > @Id > @Column(name="ID", nullable=false) > private String id = new String(); > > @Column(name="NAME") > private String name = new String(); > > @ManyToOne(cascade={CascadeType.ALL}) > @JoinColumn(name="PARENT_ID", nullable=false) > private TestParent parent = new TestParent(); > > @Override > public boolean equals(Object other) { > if (other != null && other instanceof TestChild) { > return ((TestChild)other).getId().equals(this.id); > } > > return false; > } > > @Override > public int hashCode() { > return id.hashCode(); > } > > //Skipping getters/setters > } > > > The class testing the merge() behavior looks as follows: > public class PCTester { > private EntityManager em = null; > > public PCTester() { > EntityManagerFactory emf = > Persistence.createEntityManagerFactory( > "testFactory"); > em = emf.createEntityManager(); > } > > public void mergeParent(TestParent p) { > em.getTransaction().begin(); > p = em.merge(p); > em.getTransaction().commit(); > } > > public static void main(String[] args) { > TestParent p = new TestParent(); > p.setId("1"); > p.setName("parent-1-update"); > > TestChild c = new TestChild(); > c.setId("1"); > c.setName("child-1-update"); > > p.addChild(c); > > PCTester t = new PCTester(); > t.mergeParent(p); > } > } > > Finally, the entity manager is configured as follows in persistence.xml: > <persistence-unit name="testFactory"> > > <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider> > > <class>com.lmco.jsf.alis.obphm.afrs.session.model.TestParent</class> > <class>com.lmco.jsf.alis.obphm.afrs.session.model.TestChild</class> > > <properties> > <property name="openjpa.ConnectionURL" > > > value="jdbc:oracle:thin:@PROPRIETARY"/> > <property name="openjpa.ConnectionDriverName" > value="oracle.jdbc.OracleDriver"/> > <property name="openjpa.ConnectionUserName" > value="PROPRIETARY"/> > <property name="openjpa.ConnectionPassword" > value="PROPRIETARY"/> > <property name="openjpa.Log" value="SQL=TRACE"/> > <property name="openjpa.ConnectionFactoryProperties" > value="PrettyPrint=true, PrettyPrintLineLength=72"/> > <property name="openjpa.jdbc.SchemaFactory" > value="native(foreignKeys=true)" /> > </properties> > > </persistence-unit> > > In case the database already contains parent and child records with id > "1", > the test runs without problems and both parent and child names are > correctly > updated. The SQL trace shows the following statements being executed: > > SELECT t0.NAME, t1.PARENT_ID, t1.ID, t1.NAME > FROM AFRS_USER.TEST_PARENT t0, AFRS_USER.TEST_CHILD t1 > WHERE t0.ID = ? AND t0.ID = t1.PARENT_ID(+) > ORDER BY t1.PARENT_ID ASC > [params=(String) 1] > > UPDATE AFRS_USER.TEST_PARENT > SET NAME = ? > WHERE ID = ? > [params=(String) parent-1-update, (String) 1] > > UPDATE AFRS_USER.TEST_CHILD > SET PARENT_ID = ?, NAME = ? > WHERE ID = ? > [params=(String) 1, (String) child-1-update, (String) 1] > > > However, when parent and child do not exist in the database, the merge() > operation throws an exception because the database tries to insert NULL > into > the parent table for reasons unknown to me: > > SELECT t0.NAME, t1.PARENT_ID, t1.ID, t1.NAME > FROM AFRS_USER.TEST_PARENT t0, AFRS_USER.TEST_CHILD t1 > WHERE t0.ID = ? AND t0.ID = t1.PARENT_ID(+) > ORDER BY t1.PARENT_ID ASC > [params=(String) 1] > > SELECT t0.NAME, t1.ID, t1.NAME > FROM AFRS_USER.TEST_CHILD t0, AFRS_USER.TEST_PARENT t1 > WHERE t0.ID = ? AND t0.PARENT_ID = t1.ID(+) > [params=(String) 1] > > // Unexpected!! > SELECT t0.NAME, t1.PARENT_ID, t1.ID, t1.NAME > FROM AFRS_USER.TEST_PARENT t0, AFRS_USER.TEST_CHILD t1 > WHERE t0.ID = ? AND t0.ID = t1.PARENT_ID(+) > ORDER BY t1.PARENT_ID ASC > [params=(String) ] > > INSERT INTO AFRS_USER.TEST_PARENT (ID, NAME) > VALUES (?, ?) > [params=(String) 1, (String) parent-1-update] > > INSERT INTO AFRS_USER.TEST_CHILD (ID, PARENT_ID, NAME) > VALUES (?, ?, ?) > [params=(String) 1, (String) 1, (String) child-1-update] > > // Unexpected!! > INSERT INTO AFRS_USER.TEST_PARENT (ID, NAME) > VALUES (?, ?) > [params=(String) , (String) ] > > Leading to > > Exception in thread "main" <openjpa-1.0.0-r420667:568756 fatal > store error> > org.apache.openjpa.persistence.RollbackException: The transaction has been > rolled back. See the nested exceptions for details on the errors that > occurred. > Etc... > > When creating a new parent only (i.e. without children) in the test > method, > it is correctly persisted into the database with the merge() operation, so > it seems that something goes wrong with cascading the merge to the child > object. > > Does anyone know what's the reason for the unexpected SQL statements? > > Any help is highly appreciated. > > Thanks, > > Jonatan Samoocha > > Using: > OpenJPA 1.0.0 > JDK 1.5.0_14 > Oracle 10G > > -- > View this message in context: > http://n2.nabble.com/Unexpected-merge-cascade-behavior-tp1668355p1668355.html > Sent from the OpenJPA Users mailing list archive at Nabble.com. > > -- View this message in context: http://n2.nabble.com/Unexpected-merge-cascade-behavior-tp1668355p2112406.html Sent from the OpenJPA Users mailing list archive at Nabble.com.
