mirror of
https://github.com/apache/openjpa.git
synced 2025-02-21 09:35:40 +00:00
OPENJPA-1141:
Optionally reorder MetaData resolution for entities which use derived IDs Submitted By: Jody Grassel git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@830690 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
cb31d309b2
commit
530a190ebb
@ -64,6 +64,7 @@ public class Compatibility {
|
||||
private boolean _superclassDiscriminatorStrategyByDefault = true;
|
||||
private boolean _isAbstractMappingUniDirectional = false;
|
||||
private boolean _isNonDefaultMappingAllowed = false;
|
||||
private boolean _reorderMetaDataResolution = true;
|
||||
|
||||
/**
|
||||
* Whether to require exact identity value types when creating object
|
||||
@ -472,5 +473,25 @@ public class Compatibility {
|
||||
public boolean isNonDefaultMappingAllowed() {
|
||||
return _isNonDefaultMappingAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether OpenJPA should reorder entities in MetaDataRepository.processBuffer() to ensure that the metadata for
|
||||
* entities with foreign keys in their identity are processed after the entities it depends on.
|
||||
*
|
||||
* @return true if the reordering should be performed, false if not.
|
||||
*/
|
||||
public boolean getReorderMetaDataResolution() {
|
||||
return _reorderMetaDataResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether OpenJPA should reorder entities in MetaDataRepository.processBuffer() to ensure that the metadata for
|
||||
* entities with foreign keys in their identity are processed after the entities it depends on.
|
||||
*
|
||||
* @param reorderProcessBuffer true if the reordering should be performed, false if not.
|
||||
*/
|
||||
public void setReorderMetaDataResolution(boolean reorderProcessBuffer) {
|
||||
_reorderMetaDataResolution = reorderProcessBuffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -151,6 +151,8 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
||||
private ReentrantLock _lock = null;
|
||||
protected boolean _preload = false;
|
||||
protected boolean _noLock = false;
|
||||
|
||||
private boolean _reorderMetaDataResolution = false;
|
||||
|
||||
/**
|
||||
* Default constructor. Configure via {@link Configurable}.
|
||||
@ -829,6 +831,12 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
||||
buffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Check if process buffer reordering for PCTypes that have relationships to other PCTypes in their identity
|
||||
// should be performed.
|
||||
if (_reorderMetaDataResolution) {
|
||||
processed = resolveFKInPKDependenciesOrdering(processed);
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
|
||||
@ -1773,6 +1781,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
||||
public void setConfiguration(Configuration conf) {
|
||||
_conf = (OpenJPAConfiguration) conf;
|
||||
_log = _conf.getLog(OpenJPAConfiguration.LOG_METADATA);
|
||||
_reorderMetaDataResolution = _conf.getCompatibilityInstance().getReorderMetaDataResolution();
|
||||
}
|
||||
|
||||
public void startConfiguration() {
|
||||
@ -2294,4 +2303,194 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
||||
public XMLFieldMetaData newXMLFieldMetaData(Class<?> type, String name) {
|
||||
return new XMLFieldMetaData(type, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes the list of ClassMetaData in the supplied list for any which has foreign keys to other ClassMetaData
|
||||
* instances in its identity (in other words, PCTypes which have primary keys that are foreign keys to other
|
||||
* tables), and returns a list arranged so that a ClassMetaData that depends on another ClassMetaData appears
|
||||
* after it in the list.
|
||||
*
|
||||
* @param cmdList - List of ClassMetaData to examine
|
||||
* @return - List of ClassMetaData, with ClassMetaData dependees moved after the last identified dependent
|
||||
* ClassMetaData, if any move is necessary.
|
||||
*/
|
||||
private List<ClassMetaData> resolveFKInPKDependenciesOrdering(List<ClassMetaData> cmdList) {
|
||||
HashMap<ClassMetaData, CMDDependencyNode> nodeMap = new HashMap<ClassMetaData, CMDDependencyNode>();
|
||||
HashSet<CMDDependencyNode> nodesWithDependenciesSet = new HashSet<CMDDependencyNode>();
|
||||
ArrayList<CMDDependencyNode> nodeList = new ArrayList<CMDDependencyNode>(cmdList.size());
|
||||
|
||||
// Initial analysis of ClassMetaData objects -- Populate the linked list with objects in the same order of
|
||||
// appearance in the original list. Identify CMDs whose identities have a FK to another CMD, and catalog that
|
||||
// dependency.
|
||||
for (ClassMetaData cmd : cmdList) {
|
||||
// Add this node to the list
|
||||
CMDDependencyNode node = nodeMap.get(cmd);
|
||||
if (node == null) {
|
||||
node = new CMDDependencyNode(cmd);
|
||||
nodeMap.put(cmd, node);
|
||||
}
|
||||
nodeList.add(node);
|
||||
|
||||
// Examine its primary key fields, flag any references to another PCType that is defined in cmdList as a
|
||||
// dependency
|
||||
FieldMetaData[] fmdArr = cmd.getPrimaryKeyFields();
|
||||
for (FieldMetaData fmd : fmdArr) {
|
||||
ValueMetaData vmd = fmd.getValue();
|
||||
if (vmd.isTypePC()) {
|
||||
ClassMetaData targetCMD = vmd.getDeclaredTypeMetaData();
|
||||
|
||||
// Only process entries which are in the cmdList, as we don't want to be adding anything new.
|
||||
if (!cmdList.contains(targetCMD)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Register the dependency
|
||||
CMDDependencyNode targetNode = null;
|
||||
if ((targetNode = nodeMap.get(targetCMD)) == null) {
|
||||
targetNode = new CMDDependencyNode(targetCMD);
|
||||
nodeMap.put(targetCMD, targetNode);
|
||||
}
|
||||
node.registerDependentNode(targetNode);
|
||||
nodesWithDependenciesSet.add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Analysis is complete. For each CMD that has an identity foreign key dependency on another CMD, ensure that it
|
||||
// appears later in the list then the CMD it is dependent on. If it appears earlier, move it immediately after
|
||||
// the CMD. If there are multiple CMDs the identity is dependent on, move it after the last dependency in
|
||||
// the linked list.
|
||||
for (CMDDependencyNode node : nodesWithDependenciesSet) {
|
||||
// Check if there is a cycle (dependencies or subdependencies that create a cycle in the graph. If one is
|
||||
// detected, then this algorithm cannot be used to reorder the CMD list. Emit a warning, and return the
|
||||
// original list.
|
||||
if (node.checkForCycle()) {
|
||||
if (_log.isWarnEnabled()) {
|
||||
_log.warn(_loc.get("cmd-discover-cycle", node.getCmd().getResourceName()));
|
||||
}
|
||||
return cmdList;
|
||||
}
|
||||
|
||||
int nodeIndex = nodeList.indexOf(node);
|
||||
Set<CMDDependencyNode> dependencies = node.getDependsOnSet();
|
||||
|
||||
// If the current node has a dependency that appears later in the list, then this node needs
|
||||
// to be moved to the point immediately after that dependency.
|
||||
CMDDependencyNode moveAfter = null;
|
||||
int moveAfterIndex = -1;
|
||||
for (CMDDependencyNode depNode : dependencies) {
|
||||
int dependencyIndex = nodeList.indexOf(depNode);
|
||||
if ((nodeIndex < dependencyIndex) && (moveAfterIndex < dependencyIndex)) {
|
||||
moveAfter = depNode;
|
||||
moveAfterIndex = dependencyIndex;
|
||||
}
|
||||
}
|
||||
if (moveAfter != null) {
|
||||
nodeList.remove(nodeIndex);
|
||||
nodeList.add(nodeList.indexOf(moveAfter) + 1, node);
|
||||
}
|
||||
}
|
||||
|
||||
// Sorting is complete, build the return list. Clear the dependsOnSet for the GC.
|
||||
ArrayList<ClassMetaData> returnList = new ArrayList<ClassMetaData>();
|
||||
for (CMDDependencyNode current : nodeList) {
|
||||
returnList.add(current.getCmd());
|
||||
current.getDependsOnSet().clear();
|
||||
}
|
||||
|
||||
return returnList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Linked list node class for managing any foreign keys in the identity of a ClassMetaData instance.
|
||||
*
|
||||
*/
|
||||
private class CMDDependencyNode {
|
||||
private ClassMetaData cmd;
|
||||
|
||||
// Marker for quick determination if this node has dependencies
|
||||
private boolean hasDependencies = false;
|
||||
|
||||
// List of ClassMetaData objects this ClassMetaData depends on
|
||||
private HashSet<CMDDependencyNode> dependsOnSet = new HashSet<CMDDependencyNode>();
|
||||
|
||||
/**
|
||||
* Inner class constructor
|
||||
*/
|
||||
CMDDependencyNode(ClassMetaData cmd) {
|
||||
this.cmd = cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ClassMetaData instance referenced by this node.
|
||||
*/
|
||||
public ClassMetaData getCmd() {
|
||||
return cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if this node's ClassMetaData has a FK in its identity that refers to another ClassMetaData;
|
||||
* false if it does not.
|
||||
*/
|
||||
public boolean getHasDependencies() {
|
||||
return hasDependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a ClassMetaData modelled by a CMDDependencyNode as a dependency of this ClassMetaData.
|
||||
*
|
||||
*/
|
||||
public void registerDependentNode(CMDDependencyNode node) {
|
||||
getDependsOnSet().add(node);
|
||||
hasDependencies = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Set containing all of the CMDDependencyNode instances that this node has a FK in identity
|
||||
* dependency on.
|
||||
*
|
||||
*/
|
||||
public Set<CMDDependencyNode> getDependsOnSet() {
|
||||
return dependsOnSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks all dependencies, and sub-dependencies, for any cycles in the dependency graph.
|
||||
*
|
||||
* @return true if a cycle was discovered, false if not.
|
||||
*/
|
||||
public boolean checkForCycle() {
|
||||
java.util.Stack<CMDDependencyNode> visitStack = new java.util.Stack<CMDDependencyNode>();
|
||||
return internalCheckForCycle(visitStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal implementation of the cycle detection.
|
||||
*
|
||||
* @param visitStack
|
||||
* @return true if a cycle is detected, false if no cycle was detected.
|
||||
*/
|
||||
private boolean internalCheckForCycle(java.util.Stack<CMDDependencyNode> visitStack) {
|
||||
if (visitStack.contains(this)) {
|
||||
return true;
|
||||
}
|
||||
visitStack.push(this);
|
||||
|
||||
try {
|
||||
for (CMDDependencyNode node : dependsOnSet) {
|
||||
if (node.getHasDependencies()) {
|
||||
if (node.internalCheckForCycle(visitStack) == true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
visitStack.pop();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -347,4 +347,7 @@ repos-preload-none: No persistent metadata found for loading during initializati
|
||||
The persistent classes must be enlisted in configuration to be loaded during initialization.
|
||||
repos-preloading: Following metadata are being loaded during initialization by "{0}": {1}.
|
||||
repos-preload-error: Unexpected error during early loading during initialization. \
|
||||
See nested stacktrace for details.
|
||||
See nested stacktrace for details.
|
||||
cmd-discover-cycle: A cycle was detected while resolving the identity \
|
||||
references for type "{0}". The original process buffer ordering \
|
||||
will be used.
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.persistence.identity.entityasidentity;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name="EAIAccount")
|
||||
@IdClass(AccountId.class)
|
||||
public class Account {
|
||||
@Id
|
||||
@Column(name="account_id")
|
||||
private Integer accountId;
|
||||
|
||||
@Id
|
||||
@Column(name="group_id")
|
||||
private Integer groupId;
|
||||
|
||||
@Id
|
||||
@ManyToOne(cascade = CascadeType.ALL)
|
||||
@JoinColumn(name="accountHolder_id")
|
||||
private Person accountHolder;
|
||||
|
||||
private long balanceInDollars;
|
||||
private int balanceInCents;
|
||||
private boolean accountLocked;
|
||||
|
||||
public Account() {
|
||||
|
||||
}
|
||||
|
||||
public Integer getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public void setAccountId(Integer accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
public Integer getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(Integer groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public Person getAccountHolder() {
|
||||
return accountHolder;
|
||||
}
|
||||
|
||||
public void setAccountHolder(Person accountHolder) {
|
||||
this.accountHolder = accountHolder;
|
||||
}
|
||||
|
||||
public long getBalanceInDollars() {
|
||||
return balanceInDollars;
|
||||
}
|
||||
|
||||
public void setBalanceInDollars(long balanceInDollars) {
|
||||
this.balanceInDollars = balanceInDollars;
|
||||
}
|
||||
|
||||
public int getBalanceInCents() {
|
||||
return balanceInCents;
|
||||
}
|
||||
|
||||
public void setBalanceInCents(int balanceInCents) {
|
||||
this.balanceInCents = balanceInCents;
|
||||
}
|
||||
|
||||
public boolean isAccountLocked() {
|
||||
return accountLocked;
|
||||
}
|
||||
|
||||
public void setAccountLocked(boolean accountLocked) {
|
||||
this.accountLocked = accountLocked;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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.persistence.identity.entityasidentity;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name="EAIAccountGroup")
|
||||
public class AccountGroup {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@OneToMany(cascade={CascadeType.ALL}, fetch=FetchType.LAZY)
|
||||
private Set<Account> accountSet;
|
||||
|
||||
public AccountGroup() {
|
||||
accountSet = new java.util.HashSet<Account>();
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Set<Account> getAccountSet() {
|
||||
return accountSet;
|
||||
}
|
||||
|
||||
public void setAccountSet(Set<Account> accountSet) {
|
||||
this.accountSet = accountSet;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.persistence.identity.entityasidentity;
|
||||
|
||||
public class AccountId implements java.io.Serializable {
|
||||
private static final long serialVersionUID = 4262907482129342511L;
|
||||
|
||||
private Integer accountId;
|
||||
private Integer groupId;
|
||||
private Integer accountHolder;
|
||||
|
||||
private Integer hashcode = null;
|
||||
|
||||
public AccountId() {
|
||||
|
||||
}
|
||||
|
||||
public Integer getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public void setAccountId(Integer accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
|
||||
public Integer getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(Integer groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public Integer getAccountHolder() {
|
||||
return accountHolder;
|
||||
}
|
||||
|
||||
public void setAccountHolder(Integer accountHolder) {
|
||||
this.accountHolder = accountHolder;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (o instanceof AccountId) {
|
||||
AccountId oId = (AccountId) o;
|
||||
if ( oId.accountId.equals(this.accountId) &&
|
||||
oId.accountHolder.equals(this.accountHolder) &&
|
||||
oId.groupId.equals(this.groupId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
if (hashcode == null) {
|
||||
String hashStr = this.groupId + ":" + this.accountHolder + ":" + this.accountId;
|
||||
hashcode = hashStr.hashCode();
|
||||
}
|
||||
return hashcode.intValue();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
s * 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.persistence.identity.entityasidentity;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name="EAIPerson")
|
||||
public class Person {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
|
||||
public Person() {
|
||||
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* 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.persistence.identity.entityasidentity;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Query;
|
||||
|
||||
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||
|
||||
public class TestEntityAsIdentityFields extends SingleEMFTestCase {
|
||||
public void setUp() {
|
||||
setUp(
|
||||
Account.class, AccountGroup.class, Person.class,
|
||||
"openjpa.Compatibility", "reorderMetaDataResolution=true");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for the NullPointerException in MappingInfo.mergeJoinColumn reported in OpenJPA-1141.
|
||||
*
|
||||
*/
|
||||
public void testEntityAsIdentityField001() {
|
||||
EntityManager em = null;
|
||||
em = emf.createEntityManager();
|
||||
|
||||
Query query = em.createQuery("SELECT ag from AccountGroup ag");
|
||||
List resultList = query.getResultList();
|
||||
|
||||
em.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test EntityManager persist() and find() with entities with entity relationships as
|
||||
* part of their identity. Clears persistence context between entity create and find.
|
||||
*
|
||||
*/
|
||||
public void testEntityAsIdentityField002A() {
|
||||
EntityManager em = null;
|
||||
|
||||
try {
|
||||
em = emf.createEntityManager();
|
||||
|
||||
// Create population
|
||||
createPopulation(em);
|
||||
|
||||
// Clear persistence context, fetch from database
|
||||
em.clear();
|
||||
AccountId aId = new AccountId();
|
||||
aId.setAccountId(1);
|
||||
aId.setAccountHolder(1);
|
||||
aId.setGroupId(1);
|
||||
Account findAccount = em.find(Account.class, aId);
|
||||
assertTrue(findAccount != null);
|
||||
} finally {
|
||||
// Cleanup
|
||||
if (em != null) {
|
||||
if (em.getTransaction().isActive()) {
|
||||
em.getTransaction().rollback();
|
||||
}
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test EntityManager persist() and find() with entities with entity relationships as
|
||||
* part of their identity. Does not clear persistence context between entity create and find.
|
||||
*
|
||||
*/
|
||||
public void testEntityAsIdentityField002B() {
|
||||
EntityManager em = null;
|
||||
|
||||
try {
|
||||
em = emf.createEntityManager();
|
||||
|
||||
// Create population
|
||||
createPopulation(em);
|
||||
|
||||
// Fetch from database
|
||||
AccountId aId = new AccountId();
|
||||
aId.setAccountId(1);
|
||||
aId.setAccountHolder(1);
|
||||
aId.setGroupId(1);
|
||||
Account findAccount = em.find(Account.class, aId);
|
||||
assertTrue(findAccount != null);
|
||||
} finally {
|
||||
// Cleanup
|
||||
if (em != null) {
|
||||
if (em.getTransaction().isActive()) {
|
||||
em.getTransaction().rollback();
|
||||
}
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test EntityManager persist() and find() with entities with entity relationships as
|
||||
* part of their identity. Uses different EntityManagers for create and find.
|
||||
*
|
||||
*/
|
||||
public void testEntityAsIdentityField002C() {
|
||||
EntityManager em = null;
|
||||
EntityManager emPop = null;
|
||||
|
||||
try {
|
||||
emPop = emf.createEntityManager();
|
||||
em = emf.createEntityManager();
|
||||
|
||||
// Create population
|
||||
createPopulation(emPop);
|
||||
|
||||
// Clear persistence context, fetch from database
|
||||
em.clear();
|
||||
AccountId aId = new AccountId();
|
||||
aId.setAccountId(1);
|
||||
aId.setAccountHolder(1);
|
||||
aId.setGroupId(1);
|
||||
Account findAccount = em.find(Account.class, aId);
|
||||
assertTrue(findAccount != null);
|
||||
} finally {
|
||||
// Cleanup
|
||||
if (em != null) {
|
||||
if (em.getTransaction().isActive()) {
|
||||
em.getTransaction().rollback();
|
||||
}
|
||||
em.close();
|
||||
}
|
||||
if (emPop != null) {
|
||||
if (emPop.getTransaction().isActive()) {
|
||||
emPop.getTransaction().rollback();
|
||||
}
|
||||
emPop.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a query with a where clause that crosses through the identity relationship.
|
||||
* Clear persistence context before performing the query.
|
||||
*
|
||||
*/
|
||||
public void testEntityAsIdentityField003A() {
|
||||
EntityManager em = null;
|
||||
|
||||
try {
|
||||
em = emf.createEntityManager();
|
||||
|
||||
// Create population
|
||||
createPopulation(em);
|
||||
em.clear();
|
||||
|
||||
Query query = em.createQuery("SELECT a FROM Account a WHERE a.accountHolder.id > 5");
|
||||
List resultList = query.getResultList();
|
||||
assertEquals(5, resultList.size());
|
||||
} finally {
|
||||
// Cleanup
|
||||
if (em != null) {
|
||||
if (em.getTransaction().isActive()) {
|
||||
em.getTransaction().rollback();
|
||||
}
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a query with a where clause that crosses through the identity relationship.
|
||||
* Use a separate EntityManager to populate the database, and a separate EntityManager
|
||||
* to perform the query
|
||||
*
|
||||
*/
|
||||
public void testEntityAsIdentityField004A() {
|
||||
EntityManager em = null;
|
||||
EntityManager emPop = null;
|
||||
|
||||
try {
|
||||
emPop = emf.createEntityManager();
|
||||
em = emf.createEntityManager();
|
||||
|
||||
// Create population
|
||||
createPopulation(emPop);
|
||||
em.clear();
|
||||
|
||||
Query query = em.createQuery("SELECT a FROM Account a WHERE a.accountHolder.id > 5");
|
||||
List resultList = query.getResultList();
|
||||
assertEquals(5, resultList.size());
|
||||
} finally {
|
||||
// Cleanup
|
||||
if (em != null) {
|
||||
if (em.getTransaction().isActive()) {
|
||||
em.getTransaction().rollback();
|
||||
}
|
||||
em.close();
|
||||
}
|
||||
if (emPop != null) {
|
||||
if (emPop.getTransaction().isActive()) {
|
||||
emPop.getTransaction().rollback();
|
||||
}
|
||||
emPop.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Database population
|
||||
*
|
||||
*/
|
||||
private void createPopulation(EntityManager em) {
|
||||
em.getTransaction().begin();
|
||||
|
||||
AccountGroup ag = new AccountGroup();
|
||||
ag.setId(1);
|
||||
Set<Account> agAccountSet = ag.getAccountSet();
|
||||
em.persist(ag);
|
||||
|
||||
for (int index = 1; index <= 10; index++) {
|
||||
Person peep = new Person();
|
||||
peep.setId(index);
|
||||
peep.setFirstName("John");
|
||||
peep.setLastName("Doe");
|
||||
|
||||
Account account = new Account();
|
||||
account.setAccountId(index);
|
||||
account.setAccountHolder(peep);
|
||||
account.setGroupId((index / 5) + 1);
|
||||
|
||||
account.setBalanceInCents(0);
|
||||
account.setBalanceInDollars(index * 1000);
|
||||
|
||||
em.persist(peep);
|
||||
em.persist(account);
|
||||
|
||||
agAccountSet.add(account);
|
||||
}
|
||||
|
||||
em.getTransaction().commit();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user