mirror of https://github.com/apache/openjpa.git
Reverting OPENJPA_817 in trunk. Conflict with Issue 706 causes unpredictable results
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@723914 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
b45e0655df
commit
7a6ac4afc7
|
@ -58,7 +58,7 @@ public class ConstraintUpdateManager
|
|||
(ConstraintUpdateManager.class);
|
||||
|
||||
public boolean orderDirty() {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected PreparedStatementManager newPreparedStatementManager
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.sql.SQLException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.HashMap;
|
||||
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<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;
|
||||
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;
|
||||
|
||||
// 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<PrimaryRow> _primaryOrder;
|
||||
private final List _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<PrimaryRow>() : null;
|
||||
_primaryOrder = (order) ? new ArrayList() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -80,98 +80,61 @@ public class RowManagerImpl
|
|||
* Return the ordered primary rows. Only available if ordering requested
|
||||
* on construction.
|
||||
*/
|
||||
public List<PrimaryRow> getOrdered() {
|
||||
if(_primaryOrder == null ) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _primaryOrder;
|
||||
}
|
||||
public List getOrdered() {
|
||||
return (_primaryOrder == null) ? Collections.EMPTY_LIST : _primaryOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all inserted primary rows.
|
||||
*/
|
||||
public Collection<PrimaryRow> getInserts() {
|
||||
if(_inserts == null ) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _inserts.values();
|
||||
}
|
||||
public Collection getInserts() {
|
||||
return (_inserts == null) ? Collections.EMPTY_LIST : _inserts.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all updated primary rows.
|
||||
*/
|
||||
public Collection<PrimaryRow> getUpdates() {
|
||||
if(_updates == null ){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _updates.values();
|
||||
}
|
||||
public Collection getUpdates() {
|
||||
return (_updates == null) ? Collections.EMPTY_LIST : _updates.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all deleted primary rows.
|
||||
*/
|
||||
public Collection<PrimaryRow> getDeletes() {
|
||||
if(_deletes == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _deletes.values();
|
||||
}
|
||||
public Collection getDeletes() {
|
||||
return (_deletes == null) ? Collections.EMPTY_LIST : _deletes.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all inserted and updated secondary rows.
|
||||
*/
|
||||
public Collection<SecondaryRow> getSecondaryUpdates() {
|
||||
if(_secondaryUpdates == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _secondaryUpdates;
|
||||
}
|
||||
public Collection getSecondaryUpdates() {
|
||||
return (_secondaryUpdates == null) ? Collections.EMPTY_LIST
|
||||
: _secondaryUpdates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all deleted secondary rows.
|
||||
*/
|
||||
public Collection<SecondaryRow> getSecondaryDeletes() {
|
||||
if(_secondaryDeletes == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _secondaryDeletes;
|
||||
}
|
||||
public Collection getSecondaryDeletes() {
|
||||
return (_secondaryDeletes == null) ? Collections.EMPTY_LIST
|
||||
: _secondaryDeletes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any 'all row' updates.
|
||||
*/
|
||||
public Collection<Row> getAllRowUpdates() {
|
||||
if(_allRowUpdates == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _allRowUpdates;
|
||||
}
|
||||
public Collection getAllRowUpdates() {
|
||||
return (_allRowUpdates == null) ? Collections.EMPTY_LIST
|
||||
: _allRowUpdates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any 'all row' deletes.
|
||||
*/
|
||||
public Collection<Row> getAllRowDeletes() {
|
||||
if(_allRowDeletes == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
return _allRowDeletes;
|
||||
}
|
||||
|
||||
public Collection getAllRowDeletes() {
|
||||
return (_allRowDeletes == null) ? Collections.EMPTY_LIST
|
||||
: _allRowDeletes;
|
||||
}
|
||||
|
||||
public Row getSecondaryRow(Table table, int action) {
|
||||
|
@ -186,12 +149,12 @@ public class RowManagerImpl
|
|||
SecondaryRow srow = (SecondaryRow) row;
|
||||
if (srow.getAction() == Row.ACTION_DELETE) {
|
||||
if (_secondaryDeletes == null)
|
||||
_secondaryDeletes = new ArrayList<SecondaryRow>();
|
||||
_secondaryDeletes.add((SecondaryRow) srow.clone());
|
||||
_secondaryDeletes = new ArrayList();
|
||||
_secondaryDeletes.add(srow.clone());
|
||||
} else {
|
||||
if (_secondaryUpdates == null)
|
||||
_secondaryUpdates = new ArrayList<SecondaryRow>();
|
||||
_secondaryUpdates.add((SecondaryRow) srow.clone());
|
||||
_secondaryUpdates = new ArrayList();
|
||||
_secondaryUpdates.add(srow.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,12 +169,12 @@ public class RowManagerImpl
|
|||
switch (row.getAction()) {
|
||||
case Row.ACTION_UPDATE:
|
||||
if (_allRowUpdates == null)
|
||||
_allRowUpdates = new ArrayList<Row>();
|
||||
_allRowUpdates = new ArrayList();
|
||||
_allRowUpdates.add(row);
|
||||
break;
|
||||
case Row.ACTION_DELETE:
|
||||
if (_allRowDeletes == null)
|
||||
_allRowDeletes = new ArrayList<Row>();
|
||||
_allRowDeletes = new ArrayList();
|
||||
_allRowDeletes.add(row);
|
||||
break;
|
||||
default:
|
||||
|
@ -229,25 +192,25 @@ public class RowManagerImpl
|
|||
&& _row != null && _row.getAction() == action)
|
||||
return _row;
|
||||
|
||||
Map<Key, PrimaryRow> map;
|
||||
Map map;
|
||||
if (action == Row.ACTION_DELETE) {
|
||||
if (_deletes == null && create)
|
||||
_deletes = new LinkedHashMap<Key, PrimaryRow>();
|
||||
_deletes = new HashMap();
|
||||
map = _deletes;
|
||||
} else if (action == Row.ACTION_INSERT) {
|
||||
if (_inserts == null && create)
|
||||
_inserts = new LinkedHashMap<Key, PrimaryRow>();
|
||||
_inserts = new HashMap();
|
||||
map = _inserts;
|
||||
} else {
|
||||
if (_updates == null && create)
|
||||
_updates = new LinkedHashMap<Key, PrimaryRow>();
|
||||
_updates = new HashMap();
|
||||
map = _updates;
|
||||
}
|
||||
if (map == null)
|
||||
return null;
|
||||
|
||||
_key = new Key(table, sm);
|
||||
_row = map.get(_key);
|
||||
_row = (PrimaryRow) map.get(_key);
|
||||
|
||||
if (_row == null && create) {
|
||||
_row = new PrimaryRow(table, action, sm);
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* 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,6 +21,7 @@ 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;
|
||||
|
@ -33,7 +34,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;
|
||||
|
||||
|
@ -129,28 +130,4 @@ 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