openjpa-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Sandhya Turaga <turagasa...@yahoo.com>
Subject Re: Unexpected merge/cascade behavior
Date Thu, 18 Dec 2008 19:30:16 GMT
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.

Thanks
Sandhya

--- On Thu, 12/18/08, Sandhya Turaga <turagasandy@yahoo.com> wrote:
From: Sandhya Turaga <turagasandy@yahoo.com>
Subject: Re: Unexpected merge/cascade behavior
To: users@openjpa.apache.org
Date: Thursday, December 18, 2008, 10:13 AM

Hi Jonatan,

      I have used your testcase to reproduce the problem but It is merging
fine and creating both the children and parent successfully. I have used JPA
trunk to test this. Could you please run your testcase with JPA2.0 and tell me
if you are still facing the problem?

Thanks
Sandhya

--- On Wed, 12/17/08, Jonatan Samoocha <jonatan.samoocha@ps.net> wrote:
From: Jonatan Samoocha <jonatan.samoocha@ps.net>
Subject: Unexpected merge/cascade behavior
To: users@openjpa.apache.org
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.




      


      
Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message