mirror of https://github.com/apache/openjpa.git
OPENJPA-817 fixed in trunk
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@724765 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
411382d4d9
commit
82e702867e
|
@ -58,7 +58,7 @@ public class ConstraintUpdateManager
|
|||
(ConstraintUpdateManager.class);
|
||||
|
||||
public boolean orderDirty() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected PreparedStatementManager newPreparedStatementManager
|
||||
|
@ -84,9 +84,10 @@ public class ConstraintUpdateManager
|
|||
flush(rmimpl.getAllRowUpdates(), psMgr);
|
||||
|
||||
// analyze foreign keys
|
||||
Collection inserts = rmimpl.getInserts();
|
||||
Collection updates = rmimpl.getUpdates();
|
||||
Collection deletes = rmimpl.getDeletes();
|
||||
Collection<PrimaryRow> inserts = rmimpl.getInserts();
|
||||
Collection<PrimaryRow> updates = rmimpl.getUpdates();
|
||||
Collection<PrimaryRow> deletes = rmimpl.getDeletes();
|
||||
|
||||
Graph[] graphs = new Graph[2]; // insert graph, delete graph
|
||||
analyzeForeignKeys(inserts, updates, deletes, rmimpl, graphs);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.sql.SQLException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -39,17 +39,17 @@ import org.apache.openjpa.util.InternalException;
|
|||
public class RowManagerImpl
|
||||
implements RowManager {
|
||||
|
||||
private Map _inserts = null;
|
||||
private Map _updates = null;
|
||||
private Map _deletes = null;
|
||||
private Collection _secondaryUpdates = null;
|
||||
private Collection _secondaryDeletes = null;
|
||||
private Collection _allRowUpdates = null;
|
||||
private Collection _allRowDeletes = null;
|
||||
private Map<Key, PrimaryRow> _inserts = null;
|
||||
private Map<Key, PrimaryRow> _updates = null;
|
||||
private Map<Key, PrimaryRow> _deletes = null;
|
||||
private Collection<SecondaryRow> _secondaryUpdates = null;
|
||||
private Collection<SecondaryRow> _secondaryDeletes = null;
|
||||
private Collection<Row> _allRowUpdates = null;
|
||||
private Collection<Row> _allRowDeletes = null;
|
||||
|
||||
// we maintain a list of the order of all primary rows if the user
|
||||
// wants to be able to fetch them in order
|
||||
private final List _primaryOrder;
|
||||
private final List<PrimaryRow> _primaryOrder;
|
||||
|
||||
// track whether we're dealing with any auto-inc columns
|
||||
private boolean _auto = false;
|
||||
|
@ -66,7 +66,7 @@ public class RowManagerImpl
|
|||
* @param order whether to keep track of the order in which rows are added
|
||||
*/
|
||||
public RowManagerImpl(boolean order) {
|
||||
_primaryOrder = (order) ? new ArrayList() : null;
|
||||
_primaryOrder = (order) ? new ArrayList<PrimaryRow>() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -80,61 +80,98 @@ public class RowManagerImpl
|
|||
* Return the ordered primary rows. Only available if ordering requested
|
||||
* on construction.
|
||||
*/
|
||||
public List getOrdered() {
|
||||
return (_primaryOrder == null) ? Collections.EMPTY_LIST : _primaryOrder;
|
||||
public List<PrimaryRow> getOrdered() {
|
||||
if(_primaryOrder == null ) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _primaryOrder;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all inserted primary rows.
|
||||
*/
|
||||
public Collection getInserts() {
|
||||
return (_inserts == null) ? Collections.EMPTY_LIST : _inserts.values();
|
||||
public Collection<PrimaryRow> getInserts() {
|
||||
if(_inserts == null ) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _inserts.values();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all updated primary rows.
|
||||
*/
|
||||
public Collection getUpdates() {
|
||||
return (_updates == null) ? Collections.EMPTY_LIST : _updates.values();
|
||||
public Collection<PrimaryRow> getUpdates() {
|
||||
if(_updates == null ){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _updates.values();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all deleted primary rows.
|
||||
*/
|
||||
public Collection getDeletes() {
|
||||
return (_deletes == null) ? Collections.EMPTY_LIST : _deletes.values();
|
||||
public Collection<PrimaryRow> getDeletes() {
|
||||
if(_deletes == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _deletes.values();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all inserted and updated secondary rows.
|
||||
*/
|
||||
public Collection getSecondaryUpdates() {
|
||||
return (_secondaryUpdates == null) ? Collections.EMPTY_LIST
|
||||
: _secondaryUpdates;
|
||||
public Collection<SecondaryRow> getSecondaryUpdates() {
|
||||
if(_secondaryUpdates == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _secondaryUpdates;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all deleted secondary rows.
|
||||
*/
|
||||
public Collection getSecondaryDeletes() {
|
||||
return (_secondaryDeletes == null) ? Collections.EMPTY_LIST
|
||||
: _secondaryDeletes;
|
||||
public Collection<SecondaryRow> getSecondaryDeletes() {
|
||||
if(_secondaryDeletes == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _secondaryDeletes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any 'all row' updates.
|
||||
*/
|
||||
public Collection getAllRowUpdates() {
|
||||
return (_allRowUpdates == null) ? Collections.EMPTY_LIST
|
||||
: _allRowUpdates;
|
||||
public Collection<Row> getAllRowUpdates() {
|
||||
if(_allRowUpdates == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _allRowUpdates;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any 'all row' deletes.
|
||||
*/
|
||||
public Collection getAllRowDeletes() {
|
||||
return (_allRowDeletes == null) ? Collections.EMPTY_LIST
|
||||
: _allRowDeletes;
|
||||
public Collection<Row> getAllRowDeletes() {
|
||||
if(_allRowDeletes == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _allRowDeletes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Row getSecondaryRow(Table table, int action) {
|
||||
|
@ -149,12 +186,12 @@ public class RowManagerImpl
|
|||
SecondaryRow srow = (SecondaryRow) row;
|
||||
if (srow.getAction() == Row.ACTION_DELETE) {
|
||||
if (_secondaryDeletes == null)
|
||||
_secondaryDeletes = new ArrayList();
|
||||
_secondaryDeletes.add(srow.clone());
|
||||
_secondaryDeletes = new ArrayList<SecondaryRow>();
|
||||
_secondaryDeletes.add((SecondaryRow) srow.clone());
|
||||
} else {
|
||||
if (_secondaryUpdates == null)
|
||||
_secondaryUpdates = new ArrayList();
|
||||
_secondaryUpdates.add(srow.clone());
|
||||
_secondaryUpdates = new ArrayList<SecondaryRow>();
|
||||
_secondaryUpdates.add((SecondaryRow) srow.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,12 +206,12 @@ public class RowManagerImpl
|
|||
switch (row.getAction()) {
|
||||
case Row.ACTION_UPDATE:
|
||||
if (_allRowUpdates == null)
|
||||
_allRowUpdates = new ArrayList();
|
||||
_allRowUpdates = new ArrayList<Row>();
|
||||
_allRowUpdates.add(row);
|
||||
break;
|
||||
case Row.ACTION_DELETE:
|
||||
if (_allRowDeletes == null)
|
||||
_allRowDeletes = new ArrayList();
|
||||
_allRowDeletes = new ArrayList<Row>();
|
||||
_allRowDeletes.add(row);
|
||||
break;
|
||||
default:
|
||||
|
@ -192,25 +229,25 @@ public class RowManagerImpl
|
|||
&& _row != null && _row.getAction() == action)
|
||||
return _row;
|
||||
|
||||
Map map;
|
||||
Map<Key, PrimaryRow> map;
|
||||
if (action == Row.ACTION_DELETE) {
|
||||
if (_deletes == null && create)
|
||||
_deletes = new HashMap();
|
||||
_deletes = new LinkedHashMap<Key, PrimaryRow>();
|
||||
map = _deletes;
|
||||
} else if (action == Row.ACTION_INSERT) {
|
||||
if (_inserts == null && create)
|
||||
_inserts = new HashMap();
|
||||
_inserts = new LinkedHashMap<Key, PrimaryRow>();
|
||||
map = _inserts;
|
||||
} else {
|
||||
if (_updates == null && create)
|
||||
_updates = new HashMap();
|
||||
_updates = new LinkedHashMap<Key, PrimaryRow>();
|
||||
map = _updates;
|
||||
}
|
||||
if (map == null)
|
||||
return null;
|
||||
|
||||
_key = new Key(table, sm);
|
||||
_row = (PrimaryRow) map.get(_key);
|
||||
_row = map.get(_key);
|
||||
|
||||
if (_row == null && create) {
|
||||
_row = new PrimaryRow(table, action, sm);
|
||||
|
|
|
@ -32,10 +32,13 @@ import java.util.Collections;
|
|||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import javax.transaction.Status;
|
||||
import javax.transaction.Synchronization;
|
||||
|
||||
|
@ -61,7 +64,6 @@ import org.apache.openjpa.lib.util.Localizer;
|
|||
import org.apache.openjpa.lib.util.ReferenceHashMap;
|
||||
import org.apache.openjpa.lib.util.ReferenceHashSet;
|
||||
import org.apache.openjpa.lib.util.ReferenceMap;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import org.apache.openjpa.meta.ClassMetaData;
|
||||
import org.apache.openjpa.meta.FieldMetaData;
|
||||
import org.apache.openjpa.meta.MetaDataRepository;
|
||||
|
@ -3310,7 +3312,7 @@ public class BrokerImpl
|
|||
Object obj;
|
||||
StateManagerImpl sm;
|
||||
ClassMetaData meta;
|
||||
Collection sms = new HashSet(objs.size());
|
||||
Collection sms = new LinkedHashSet(objs.size());
|
||||
List exceps = null;
|
||||
for (Iterator itr = objs.iterator(); itr.hasNext();) {
|
||||
obj = itr.next();
|
||||
|
@ -3637,7 +3639,7 @@ public class BrokerImpl
|
|||
try {
|
||||
assertActiveTransaction();
|
||||
|
||||
Collection sms = new HashSet(objs.size());
|
||||
Collection sms = new LinkedHashSet(objs.size());
|
||||
Object obj;
|
||||
StateManagerImpl sm;
|
||||
for (Iterator itr = objs.iterator(); itr.hasNext();) {
|
||||
|
@ -3815,7 +3817,7 @@ public class BrokerImpl
|
|||
protected Collection getPendingTransactionalStates() {
|
||||
if (_pending == null)
|
||||
return Collections.EMPTY_SET;
|
||||
return new HashSet(_pending);
|
||||
return new LinkedHashSet(_pending);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4508,7 +4510,7 @@ public class BrokerImpl
|
|||
// size may not be entirely accurate due to refs expiring, so
|
||||
// manually copy each object; doesn't matter this way if size too
|
||||
// big by some
|
||||
Set copy = new HashSet(size());
|
||||
Set copy = new LinkedHashSet(size());
|
||||
if (_dirty != null)
|
||||
for (Iterator itr = _dirty.iterator(); itr.hasNext();)
|
||||
copy.add(itr.next());
|
||||
|
@ -4524,7 +4526,7 @@ public class BrokerImpl
|
|||
public Collection copyDirty() {
|
||||
if (_dirty == null || _dirty.isEmpty())
|
||||
return Collections.EMPTY_SET;
|
||||
return new HashSet(_dirty);
|
||||
return new LinkedHashSet(_dirty);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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 java.util.Collection;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Version;
|
||||
|
||||
@Entity
|
||||
// Try not to collide with other Employee entities
|
||||
@Table(name = "PER_JDBC_KERN_EMP")
|
||||
public class Employee {
|
||||
|
||||
@Id
|
||||
private int id;
|
||||
|
||||
@Version
|
||||
private int version;
|
||||
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
|
||||
@OneToMany(mappedBy = "employee", cascade = { CascadeType.MERGE,
|
||||
CascadeType.PERSIST })
|
||||
private Collection<Task> tasks;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public Collection<Task> getTasks() {
|
||||
return tasks;
|
||||
}
|
||||
|
||||
public void setTasks(Collection<Task> tasks) {
|
||||
this.tasks = tasks;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
}
|
|
@ -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.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Version;
|
||||
|
||||
@Entity
|
||||
@Table(name = "PER_JDBC_KERN_STORY") // try not to collide
|
||||
public class Story {
|
||||
@Id
|
||||
private int id;
|
||||
|
||||
@Version
|
||||
private int version;
|
||||
|
||||
@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST })
|
||||
private Task task;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Task getTask() {
|
||||
return task;
|
||||
}
|
||||
|
||||
public void setTask(Task task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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 java.util.Collection;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Version;
|
||||
|
||||
@Entity
|
||||
@Table(name = "PER_JDBC_KERN_TASK")
|
||||
// try not to collide
|
||||
public class Task {
|
||||
@Id
|
||||
private int id;
|
||||
|
||||
@Version
|
||||
private int version;
|
||||
|
||||
@OneToMany(mappedBy = "task", cascade = { CascadeType.MERGE,
|
||||
CascadeType.PERSIST })
|
||||
private Collection<Story> stories;
|
||||
|
||||
@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST })
|
||||
private Employee employee;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Collection<Story> getStories() {
|
||||
return stories;
|
||||
}
|
||||
|
||||
public void setStories(Collection<Story> stories) {
|
||||
this.stories = stories;
|
||||
}
|
||||
|
||||
public Employee getEmployee() {
|
||||
return employee;
|
||||
}
|
||||
|
||||
public void setEmployee(Employee employee) {
|
||||
this.employee = employee;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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 java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.apache.openjpa.persistence.test.SQLListenerTestCase;
|
||||
|
||||
/**
|
||||
* Test that insert order is preserved when using the ConstraintUpdateManager
|
||||
* for entities which are not annotated with ForeignKey constraints.
|
||||
*/
|
||||
public class TestInsertOrder extends SQLListenerTestCase {
|
||||
private String empTableName;
|
||||
private String taskTableName;
|
||||
private String storyTableName;
|
||||
|
||||
public void setUp() {
|
||||
setUp(Employee.class, Task.class, Story.class);
|
||||
empTableName = getMapping(Employee.class).getTable().getFullName();
|
||||
taskTableName = getMapping(Task.class).getTable().getFullName();
|
||||
storyTableName = getMapping(Story.class).getTable().getFullName();
|
||||
}
|
||||
|
||||
/**
|
||||
* <P>Persist an Employee entity and allow the cascade to insert the children.
|
||||
* The inserts should be executed in this order, Employee, Task, Story.
|
||||
* </P>
|
||||
*
|
||||
* <P>
|
||||
* Originally this test would pass in some scenarios. I believe the order
|
||||
* relied on the hashcode of the underlying entities.
|
||||
* </P>
|
||||
*/
|
||||
public void testCascadePersist() {
|
||||
Employee e = newTree(10);
|
||||
EntityManager em = emf.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
em.persist(e);
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
|
||||
assertSQLOrder("INSERT INTO " + empTableName + ".*", "INSERT INTO "
|
||||
+ taskTableName + ".*", "INSERT INTO " + storyTableName + ".*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge an Employee entity and allow the cascade to insert the children.
|
||||
* The inserts should be executed in this order, Employee, Task, Story.
|
||||
*/
|
||||
public void testCascadeMerge() {
|
||||
Employee e = newTree(11);
|
||||
EntityManager em = emf.createEntityManager();
|
||||
em.getTransaction().begin();
|
||||
em.merge(e);
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
|
||||
assertSQLOrder("INSERT INTO " + empTableName + ".*", "INSERT INTO "
|
||||
+ taskTableName + ".*", "INSERT INTO " + storyTableName + ".*");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper to create a tree of entities
|
||||
*
|
||||
* @param id
|
||||
* ID for the entities.
|
||||
* @return an unmanaged Employee instance with the appropriate relationships
|
||||
* set.
|
||||
*/
|
||||
private Employee newTree(int id) {
|
||||
Employee e = new Employee();
|
||||
e.setId(id);
|
||||
|
||||
Task t = new Task();
|
||||
t.setId(id);
|
||||
|
||||
Story s = new Story();
|
||||
s.setId(id);
|
||||
|
||||
Collection<Task> tasks = new ArrayList<Task>();
|
||||
tasks.add(t);
|
||||
|
||||
Collection<Story> stories = new ArrayList<Story>();
|
||||
stories.add(s);
|
||||
|
||||
e.setTasks(tasks);
|
||||
t.setEmployee(e);
|
||||
|
||||
t.setStories(stories);
|
||||
s.setTask(t);
|
||||
|
||||
return e;
|
||||
}
|
||||
}
|
|
@ -21,7 +21,6 @@ package org.apache.openjpa.persistence.test;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.openjpa.lib.jdbc.AbstractJDBCListener;
|
||||
import org.apache.openjpa.lib.jdbc.JDBCEvent;
|
||||
|
@ -34,7 +33,7 @@ import org.apache.openjpa.lib.jdbc.JDBCListener;
|
|||
*/
|
||||
public abstract class SQLListenerTestCase
|
||||
extends SingleEMFTestCase {
|
||||
|
||||
private static String _nl = System.getProperty("line.separator");
|
||||
protected List<String> sql = new ArrayList<String>();
|
||||
protected int sqlCount;
|
||||
|
||||
|
@ -130,4 +129,28 @@ public abstract class SQLListenerTestCase
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void assertSQLOrder(String... expected) {
|
||||
int hits = 0;
|
||||
|
||||
for (String executedSQL : sql) {
|
||||
if (executedSQL.matches(expected[hits])) {
|
||||
hits++;
|
||||
}
|
||||
}
|
||||
|
||||
if (hits != expected.length) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Did not find SQL in expected order : ").append(_nl);
|
||||
for (String s : expected) {
|
||||
sb.append(s).append(_nl);
|
||||
}
|
||||
|
||||
sb.append("SQL Statements issued : ");
|
||||
for (String s : sql) {
|
||||
sb.append(s).append(_nl);
|
||||
}
|
||||
fail(sb.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue