mirror of https://github.com/apache/openjpa.git
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. git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@535379 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
33aa3cb59f
commit
80671afcbf
|
@ -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.Connection;
|
|||
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.jdbc.sql.SQLExceptions;
|
|||
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 @@ public class OperationOrderUpdateManager
|
|||
|
||||
// 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 @@ public class OperationOrderUpdateManager
|
|||
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);
|
||||
|
||||
|
@ -106,14 +119,122 @@ public class OperationOrderUpdateManager
|
|||
return exceps;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class OperationOrderUpdateManager
|
|||
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 @@ public class OperationOrderUpdateManager
|
|||
* 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;
|
||||
|
@ -172,6 +299,13 @@ public class OperationOrderUpdateManager
|
|||
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
|
||||
// inserted after we are; if row is dependent on itself and no
|
||||
// fk, must be an auto-inc because otherwise we wouldn't have
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue