You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by mi...@apache.org on 2009/10/28 18:34:45 UTC
svn commit: r830690 - in /openjpa/trunk:
openjpa-kernel/src/main/java/org/apache/openjpa/conf/
openjpa-kernel/src/main/java/org/apache/openjpa/meta/
openjpa-kernel/src/main/resources/org/apache/openjpa/meta/
openjpa-persistence-jdbc/src/test/java/org/a...
Author: mikedd
Date: Wed Oct 28 17:34:45 2009
New Revision: 830690
URL: http://svn.apache.org/viewvc?rev=830690&view=rev
Log:
OPENJPA-1141:
Optionally reorder MetaData resolution for entities which use derived IDs
Submitted By: Jody Grassel
Added:
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/Account.java (with props)
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/AccountGroup.java (with props)
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/AccountId.java (with props)
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/Person.java (with props)
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/TestEntityAsIdentityFields.java (with props)
Modified:
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java
openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java?rev=830690&r1=830689&r2=830690&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/conf/Compatibility.java Wed Oct 28 17:34:45 2009
@@ -64,6 +64,7 @@
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 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;
+ }
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java?rev=830690&r1=830689&r2=830690&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataRepository.java Wed Oct 28 17:34:45 2009
@@ -151,6 +151,8 @@
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 @@
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 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 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;
+ }
+ }
}
Modified: openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties?rev=830690&r1=830689&r2=830690&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties (original)
+++ openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/meta/localizer.properties Wed Oct 28 17:34:45 2009
@@ -347,4 +347,7 @@
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.
\ No newline at end of file
+ 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.
\ No newline at end of file
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/Account.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/Account.java?rev=830690&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/Account.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/Account.java Wed Oct 28 17:34:45 2009
@@ -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;
+ }
+
+
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/Account.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/AccountGroup.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/AccountGroup.java?rev=830690&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/AccountGroup.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/AccountGroup.java Wed Oct 28 17:34:45 2009
@@ -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;
+ }
+
+
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/AccountGroup.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/AccountId.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/AccountId.java?rev=830690&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/AccountId.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/AccountId.java Wed Oct 28 17:34:45 2009
@@ -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();
+ }
+
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/AccountId.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/Person.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/Person.java?rev=830690&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/Person.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/Person.java Wed Oct 28 17:34:45 2009
@@ -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;
+ }
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/Person.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/TestEntityAsIdentityFields.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/TestEntityAsIdentityFields.java?rev=830690&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/TestEntityAsIdentityFields.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/TestEntityAsIdentityFields.java Wed Oct 28 17:34:45 2009
@@ -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();
+ }
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/identity/entityasidentity/TestEntityAsIdentityFields.java
------------------------------------------------------------------------------
svn:eol-style = native