You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pc...@apache.org on 2007/05/04 22:58:50 UTC
svn commit: r535379 - in /incubator/openjpa/trunk:
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/
Author: pcl
Date: Fri May 4 13:58:49 2007
New Revision: 535379
URL: http://svn.apache.org/viewvc?view=rev&rev=535379
Log:
OPENJPA-235. Reformatted code to meet OpenJPA conventions; widened some type arguments that seemed unnecessarily narrow.
This passes all the OpenJPA tests in my environment, and the logic seems sound. I think that we could adjust the algorithm to require less collection copying, but I don't think that we should hold up the commit for that type of optimization.
Added:
incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/
incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityA.java
incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityB.java
incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityC.java
incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityD.java
incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/TestNoForeignKeyViolation.java
Modified:
incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/OperationOrderUpdateManager.java
Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/OperationOrderUpdateManager.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/OperationOrderUpdateManager.java?view=diff&rev=535379&r1=535378&r2=535379
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/OperationOrderUpdateManager.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/OperationOrderUpdateManager.java Fri May 4 13:58:49 2007
@@ -14,7 +14,7 @@
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
- * under the License.
+ * under the License.
*/
package org.apache.openjpa.jdbc.kernel;
@@ -22,8 +22,13 @@
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
+import java.util.Stack;
+import java.util.Map;
+import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.schema.ForeignKey;
import org.apache.openjpa.jdbc.sql.PrimaryRow;
import org.apache.openjpa.jdbc.sql.Row;
@@ -34,7 +39,7 @@
import org.apache.openjpa.kernel.OpenJPAStateManager;
/**
- * Update manager that writes SQL in object-level operation order.
+ * Update manager that writes SQL in object-level operation order
*
* @author Abe White
*/
@@ -66,13 +71,20 @@
// now do any 'all row' updates, which typically null keys
flush(rmimpl.getAllRowUpdates(), psMgr);
+
+ // map statemanagers to primaryrows
+ Map smMap = mapStateManagers(rmimpl.getOrdered());
+
+ // order rows to avoid constraint violations
+ List orderedRows = orderRows(rmimpl, smMap);
// gather any updates we need to avoid fk constraints on deletes
Collection constraintUpdates = null;
- for (Iterator itr = rmimpl.getDeletes().iterator(); itr.hasNext();) {
+ for (Iterator itr = orderedRows.iterator(); itr.hasNext();) {
try {
constraintUpdates = analyzeDeleteConstraints(rmimpl,
- (PrimaryRow) itr.next(), constraintUpdates);
+ (PrimaryRow) itr.next(), constraintUpdates, smMap,
+ orderedRows);
} catch (SQLException se) {
exceps = addException(exceps, SQLExceptions.getStore
(se, dict));
@@ -82,17 +94,18 @@
flush(constraintUpdates, psMgr);
constraintUpdates.clear();
}
-
+
// flush primary rows in order
- for (Iterator itr = rmimpl.getOrdered().iterator(); itr.hasNext();) {
+ for (Iterator itr = orderedRows.iterator(); itr.hasNext();) {
try {
constraintUpdates = flushPrimaryRow(rmimpl, (PrimaryRow)
- itr.next(), psMgr, constraintUpdates);
+ itr.next(), psMgr, constraintUpdates, smMap, orderedRows);
} catch (SQLException se) {
exceps = addException(exceps, SQLExceptions.getStore
(se, dict));
}
}
+
if (constraintUpdates != null)
flush(constraintUpdates, psMgr);
@@ -107,13 +120,121 @@
}
/**
+ * Reorders all rows provided by the specified RowManagerImpl such that
+ * no foreign key constraints are violated (assuming a proper schema).
+ * @param rmimpl RowManagerImpl
+ */
+ private List orderRows(RowManagerImpl rmimpl, Map smMap) {
+ List orderedRows = new ArrayList();
+ if (rmimpl.getOrdered().size() > 0) {
+ List inserts = new ArrayList(rmimpl.getInserts());
+ List updates = new ArrayList(rmimpl.getUpdates());
+ List deletes = new ArrayList(rmimpl.getDeletes());
+
+ orderedRows.addAll(orderRows(inserts, smMap));
+ orderedRows.addAll(updates);
+ orderedRows.addAll(orderRows(deletes, smMap));
+ }
+ return orderedRows;
+ }
+
+ private List orderRows(List unorderedList, Map smMap) {
+ List orderedList = new ArrayList();
+ // this iterates in a while loop instead of with an iterator to
+ // avoid ConcurrentModificationExceptions, as unorderedList is
+ // mutated in the orderRow() invocation.
+ while (!unorderedList.isEmpty()) {
+ PrimaryRow nextRow = (PrimaryRow) unorderedList.get(0);
+ orderRow(nextRow, unorderedList, orderedList, smMap, new Stack());
+ }
+ return orderedList;
+ }
+
+ private void orderRow(PrimaryRow currentRow, Collection unordered,
+ List orderedList, Map smMap, Stack visitedRows) {
+ if (orderedList.contains(currentRow)) {
+ return;
+ }
+
+ // a circular reference found which means there is a problem
+ // with the underlying database schema and/or class metadata
+ // definitions. nothing can be done here to correct the problem.
+ if (visitedRows.contains(currentRow)) {
+ orderedList.addAll(unordered);
+ unordered.clear();
+ return;
+ }
+
+ if (currentRow.getAction() == Row.ACTION_INSERT) {
+ ForeignKey[] fks = currentRow.getTable().getForeignKeys();
+ OpenJPAStateManager sm;
+ for (int i = 0; i < fks.length; i++) {
+ sm = currentRow.getForeignKeySet(fks[i]);
+ if (sm == null)
+ continue;
+ // if the foreign key is new and it's primary key is
+ // auto assigned
+ PrimaryRow fkRow = (PrimaryRow) smMap.get(sm);
+ if (fkRow.getAction() == Row.ACTION_INSERT) {
+ boolean nullable = true;
+ Column[] columns = fks[i].getColumns();
+ for (int j = 0; j < columns.length; j++) {
+ if (columns[j].isNotNull()) {
+ nullable = false;
+ break;
+ }
+ }
+ if (!nullable) {
+ visitedRows.push(currentRow);
+ PrimaryRow nextRow = (PrimaryRow) smMap.get(sm);
+ orderRow(nextRow, unordered, orderedList, smMap,
+ visitedRows);
+ visitedRows.pop();
+ }
+ }
+ }
+ if (!orderedList.contains(currentRow)) {
+ unordered.remove(currentRow);
+ orderedList.add(currentRow);
+ }
+ } else if (currentRow.getAction() == Row.ACTION_DELETE) {
+ ForeignKey[] fks = currentRow.getTable().getForeignKeys();
+ OpenJPAStateManager sm;
+ for (int i = 0; i < fks.length; i++) {
+ sm = currentRow.getForeignKeySet(fks[i]);
+ if (sm == null)
+ continue;
+ PrimaryRow fkRow = (PrimaryRow) smMap.get(sm);
+ // if the foreign key is going to be deleted
+ if (!orderedList.contains(fkRow)
+ && fkRow.getAction() == Row.ACTION_DELETE) {
+ visitedRows.add(currentRow);
+ orderRow(fkRow, unordered, orderedList, smMap, visitedRows);
+ visitedRows.remove(currentRow);
+ }
+ }
+ unordered.remove(currentRow);
+ orderedList.add(0, currentRow);
+ }
+ }
+
+ private Map mapStateManagers(List rowList) {
+ Map smMap = new HashMap();
+ for (Iterator iter = rowList.iterator(); iter.hasNext();) {
+ PrimaryRow row = (PrimaryRow) iter.next();
+ smMap.put(row.getPrimaryKey(), row);
+ }
+ return smMap;
+ }
+
+ /**
* Analyze the delete constraints on the given row, gathering necessary
* updates to null fks before deleting.
*/
private Collection analyzeDeleteConstraints(RowManagerImpl rowMgr,
- PrimaryRow row, Collection updates)
+ PrimaryRow row, Collection updates, Map smMap, List orderedRows)
throws SQLException {
- if (!row.isValid())
+ if (!row.isValid() || row.getAction() != Row.ACTION_DELETE)
return updates;
ForeignKey[] fks = row.getTable().getForeignKeys();
@@ -127,6 +248,11 @@
sm = row.getForeignKeyWhere(fks[i]);
if (sm == null)
continue;
+ PrimaryRow fkRow = (PrimaryRow) smMap.get(sm);
+ int fkIndex = orderedRows.indexOf(fkRow);
+ int rIndex = orderedRows.indexOf(row);
+ if (fkIndex > rIndex)
+ continue;
// only need an update if we have an fk to a row that's being
// deleted before we are
@@ -152,7 +278,8 @@
* Flush the given row, creating deferred updates for dependencies.
*/
private Collection flushPrimaryRow(RowManagerImpl rowMgr, PrimaryRow row,
- PreparedStatementManager psMgr, Collection updates)
+ PreparedStatementManager psMgr, Collection updates, Map smMap,
+ List orderedRows)
throws SQLException {
if (!row.isValid())
return updates;
@@ -170,6 +297,13 @@
for (int i = 0; i < fks.length; i++) {
sm = row.getForeignKeySet(fks[i]);
if (sm == null)
+ continue;
+
+ PrimaryRow fkRow = (PrimaryRow) smMap.get(sm);
+ int fkIndex = orderedRows.indexOf(fkRow);
+ int rIndex = orderedRows.indexOf(row);
+ // consider sm flushed, no need to defer
+ if (rIndex > fkIndex)
continue;
// only need an update if we have an fk to a row that's being
Added: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityA.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityA.java?view=auto&rev=535379
==============================================================================
--- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityA.java (added)
+++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityA.java Fri May 4 13:58:49 2007
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.jdbc.kernel;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.Version;
+
+import org.apache.openjpa.persistence.jdbc.ForeignKey;
+
+@Entity
+public class EntityA {
+
+ @Id
+ @Column(name = "entitya_id", nullable = false)
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Integer id;
+
+ private String name;
+
+ @OneToOne(cascade = CascadeType.ALL, optional = false)
+ @JoinColumn(name = "entityb_id", referencedColumnName = "entityb_id",
+ nullable = false)
+ @ForeignKey
+ private EntityB entityB;
+
+ @Version
+ private Integer optLock;
+
+ public EntityA() {
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public EntityB getEntityB() {
+ return this.entityB;
+ }
+
+ public void setEntityB(EntityB entityB) {
+ this.entityB = entityB;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
+
Added: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityB.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityB.java?view=auto&rev=535379
==============================================================================
--- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityB.java (added)
+++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityB.java Fri May 4 13:58:49 2007
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.jdbc.kernel;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.Version;
+
+import org.apache.openjpa.persistence.jdbc.ForeignKey;
+
+@Entity
+public class EntityB {
+
+ @Id
+ @Column(name = "entityb_id", nullable = false)
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Integer id;
+
+ private String name;
+
+ @OneToOne(cascade = CascadeType.ALL, optional = false)
+ @JoinColumn(name = "entityc_id", referencedColumnName = "entityc_id",
+ nullable = false)
+ @ForeignKey
+ private EntityC entityC;
+
+ @Version
+ private Integer optLock;
+
+ public EntityB() {
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public EntityC getEntityC() {
+ return this.entityC;
+ }
+
+ public void setEntityC(EntityC entityC) {
+ this.entityC = entityC;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
+
Added: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityC.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityC.java?view=auto&rev=535379
==============================================================================
--- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityC.java (added)
+++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityC.java Fri May 4 13:58:49 2007
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.jdbc.kernel;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
+import javax.persistence.Version;
+
+import org.apache.openjpa.persistence.Dependent;
+import org.apache.openjpa.persistence.jdbc.ForeignKey;
+
+@Entity
+public class EntityC {
+
+ @Id
+ @Column(name = "entityc_id", nullable = false)
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Integer id;
+
+ private String name;
+
+ @OneToOne(cascade = CascadeType.ALL, optional = false)
+ @JoinColumn(name = "entityd_id", referencedColumnName = "entityd_id",
+ nullable = false)
+ @ForeignKey
+ @Dependent
+ private EntityD entityD;
+
+ @Version
+ private Integer optLock;
+
+ public EntityC() {
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public EntityD getEntityD() {
+ return this.entityD;
+ }
+
+ public void setEntityD(EntityD entityD) {
+ this.entityD = entityD;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
+
Added: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityD.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityD.java?view=auto&rev=535379
==============================================================================
--- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityD.java (added)
+++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/EntityD.java Fri May 4 13:58:49 2007
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.jdbc.kernel;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Version;
+
+@Entity
+public class EntityD {
+
+ @Id
+ @Column(name = "entityd_id", nullable = false)
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Integer id;
+
+ private String name;
+
+ @Version
+ private Integer optLock;
+
+ public EntityD() {
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
+
Added: incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/TestNoForeignKeyViolation.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/TestNoForeignKeyViolation.java?view=auto&rev=535379
==============================================================================
--- incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/TestNoForeignKeyViolation.java (added)
+++ incubator/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/TestNoForeignKeyViolation.java Fri May 4 13:58:49 2007
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.jdbc.kernel;
+
+import javax.persistence.EntityManager;
+
+import junit.textui.TestRunner;
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+/**
+ * Test that sql statements get flushed in an order which does not violate
+ * non-nullable foreign key constraints on inserts and deletes.
+ *
+ * @author Reece Garrett
+ */
+public class TestNoForeignKeyViolation
+ extends SingleEMFTestCase {
+
+ private EntityA entityA;
+ private EntityC entityC;
+
+ public void setUp() {
+ setUp(EntityA.class, EntityB.class, EntityC.class, EntityD.class);
+
+ entityA = new EntityA();
+ EntityB entityB = new EntityB();
+ entityC = new EntityC();
+ EntityD entityD = new EntityD();
+ entityA.setName("entityA");
+ entityB.setName("entityB");
+ entityC.setName("entityC");
+ entityD.setName("entityD");
+ entityA.setEntityB(entityB);
+ entityB.setEntityC(entityC);
+ entityC.setEntityD(entityD);
+ }
+
+ public void testSqlOrder() {
+
+ EntityManager em = emf.createEntityManager();
+ try {
+ em.getTransaction().begin();
+ em.persist(entityA);
+ em.getTransaction().commit();
+
+ EntityD newEntityD = new EntityD();
+ newEntityD.setName("newEntityD");
+ entityC.setEntityD(newEntityD);
+
+ em.getTransaction().begin();
+ em.merge(entityC);
+ em.getTransaction().commit();
+ }
+ finally {
+ em.close();
+ }
+ }
+
+ public static void main(String[] args) {
+ TestRunner.run(TestNoForeignKeyViolation.class);
+ }
+}