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/12/16 05:17:44 UTC

svn commit: r891120 - in /openjpa/trunk: openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/mo...

Author: mikedd
Date: Wed Dec 16 04:17:43 2009
New Revision: 891120

URL: http://svn.apache.org/viewvc?rev=891120&view=rev
Log:
OPENJPA-714:
Check l1 cache when looking for managed instances when cascading.
Submitted By: Jody Grassel

Added:
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/TestCascadeOneToManyMerge.java   (with props)
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/model/
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/model/Toy.java   (with props)
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/model/ToyBox.java   (with props)
Modified:
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AttachStrategy.java

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AttachStrategy.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AttachStrategy.java?rev=891120&r1=891119&r2=891120&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AttachStrategy.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AttachStrategy.java Wed Dec 16 04:17:43 2009
@@ -264,21 +264,27 @@
      * Return a managed, possibly hollow reference for the given detached
      * object.
      */
-    protected Object getReference(AttachManager manager, Object toAttach,
-        OpenJPAStateManager sm, ValueMetaData vmd) {
+    protected Object getReference(AttachManager manager, Object toAttach, OpenJPAStateManager sm, ValueMetaData vmd) {
         if (toAttach == null)
             return null;
 
-        if (manager.getBroker().isNew(toAttach)
-            || manager.getBroker().isPersistent(toAttach)) {
+        if (manager.getBroker().isNew(toAttach)) {
+            // Check if toAttach is already mapped to a managed instance
+            PersistenceCapable pc = manager.getAttachedCopy(toAttach);
+            if (pc != null) {
+                return pc;
+            } else {
+                return toAttach;
+            }
+        } else if (manager.getBroker().isPersistent(toAttach)) {
             return toAttach;
         } else if (manager.getBroker().isDetached(toAttach)) {
             Object oid = manager.getDetachedObjectId(toAttach);
-            if (oid != null)
+            if (oid != null) {
                 return manager.getBroker().find(oid, false, null);
+            }
         }
-        throw new UserException(_loc.get("cant-cascade-attach", vmd))
-            .setFailedObject(toAttach);
+        throw new UserException(_loc.get("cant-cascade-attach", vmd)).setFailedObject(toAttach);
     }
 
     /**

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/TestCascadeOneToManyMerge.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/TestCascadeOneToManyMerge.java?rev=891120&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/TestCascadeOneToManyMerge.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/TestCascadeOneToManyMerge.java Wed Dec 16 04:17:43 2009
@@ -0,0 +1,150 @@
+/*
+ * 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.merge;
+
+import javax.persistence.EntityManager;
+
+import org.apache.openjpa.persistence.merge.model.Toy;
+import org.apache.openjpa.persistence.merge.model.ToyBox;
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+public class TestCascadeOneToManyMerge extends SingleEMFTestCase {
+    public void setUp() {
+        setUp(Toy.class, ToyBox.class, CLEAR_TABLES);
+    }
+
+    /**
+     * Create an instance of Toy and Toybox, establish the bidirectional relationship between the two, and call
+     * em.merge() on the instance of Toybox. The merge should cascade across the inverse relationship, adding both
+     * entities to the persistence context. The reference to Toy by the owning side of the relationship should be
+     * updated to point to the managed instance (Toy' because of the merge op).
+     * 
+     */
+    public void testOneToManyCascadeMergeSingleEntity() {
+        EntityManager em = emf.createEntityManager();
+
+        try {
+            // Create toy
+            Toy toy = new Toy(1);
+            toy.setToyName("Toy Train");
+
+            // Create toybox
+            ToyBox toybox = new ToyBox(1);
+            toybox.setOwnerName("Evan");
+
+            // Establish relationship
+            toy.setToybox(toybox);
+            toybox.getToyList().add(toy);
+
+            // Perform the merge
+            em.getTransaction().begin();
+            ToyBox mergedToyBox = em.merge(toybox);
+            assertNotNull("Assert em.merge() didn't return null", mergedToyBox);
+
+            // Verify the merge
+            ToyBox toyboxFind = em.find(ToyBox.class, 1);
+            Toy toyFind = em.find(Toy.class, 1);
+            assertNotNull("Assert em.find() for ToyBox(id=1) did not return null.", toyboxFind);
+            assertNotNull("Assert em.find() for Toy(id=1) did not return null.", toyFind);
+            assertTrue("Assert em.find() returns the ToyBox returned by em.merge()", mergedToyBox == toyboxFind);
+            assertTrue("Assert tahat ToyBox(id=1).toyList is size 1", toyboxFind.getToyList().size() == 1);
+            assertTrue("Assert that ToyBox(id=1).toyList contains the managed Toy(id=1).", toyboxFind.getToyList()
+                .contains(toyFind));
+            assertTrue("Assert that Toy(id=1) references the managed ToyBox(id=1).", toyFind.getToybox() == toyboxFind);
+
+            em.getTransaction().commit();
+
+            // Verify successful save to the database
+            em.clear();
+            assertNotNull("Assert em.find(Toy.class, 1) doesn't return null.", em.find(Toy.class, 1));
+            assertNotNull("Assert em.find(ToyBox.class, 1) doesn't return null.", em.find(ToyBox.class, 1));
+        } finally {
+            if (em != null) {
+                if (em.getTransaction().isActive())
+                    em.getTransaction().rollback();
+                em.close();
+            }
+        }
+    }
+
+    /**
+     * Create an instance of Toys (2) and Toybox, establish the bidirectional relationship between the two, and call
+     * em.merge() on the instance of Toybox. The merge should cascade across the inverse relationship, adding all
+     * entities to the persistence context. The reference to the Toys by the owning side of the relationship should be
+     * updated to point to the managed instance (Toy' because of the merge op).
+     * 
+     */
+    public void testOneToManyCascadeMergeDoubleEntity() {
+        EntityManager em = emf.createEntityManager();
+
+        try {
+            // Create toys
+            Toy toy1 = new Toy(1);
+            toy1.setToyName("Toy Train");
+
+            Toy toy2 = new Toy(2);
+            toy2.setToyName("Toy Plane");
+
+            // Create toybox
+            ToyBox toybox = new ToyBox(1);
+            toybox.setOwnerName("Evan");
+
+            // Establish relationship
+            toy1.setToybox(toybox);
+            toy2.setToybox(toybox);
+            toybox.getToyList().add(toy1);
+            toybox.getToyList().add(toy2);
+
+            // Perform the merge
+            em.getTransaction().begin();
+            ToyBox mergedToyBox = em.merge(toybox);
+            assertNotNull("Assert em.merge() didn't return null", mergedToyBox);
+            em.getTransaction().commit();
+
+            // Verify the merge
+            ToyBox toyboxFind = em.find(ToyBox.class, 1);
+            Toy toy1Find = em.find(Toy.class, 1);
+            Toy toy2Find = em.find(Toy.class, 2);
+            assertNotNull("Assert em.find() for ToyBox(id=1) did not return null.", toyboxFind);
+            assertNotNull("Assert em.find() for Toy(id=1) did not return null.", toy1Find);
+            assertNotNull("Assert em.find() for Toy(id=2) did not return null.", toy2Find);
+            assertTrue("Assert em.find() returns the ToyBox returned by em.merge()", mergedToyBox == toyboxFind);
+            assertTrue("Assert tahat ToyBox(id=1).toyList is size 2", toyboxFind.getToyList().size() == 2);
+            assertTrue("Assert that ToyBox(id=1).toyList contains the managed Toy(id=1).", toyboxFind.getToyList()
+                .contains(toy1Find));
+            assertTrue("Assert that ToyBox(id=1).toyList contains the managed Toy(id=2).", toyboxFind.getToyList()
+                .contains(toy2Find));
+            assertTrue("Assert that Toy(id=1) references the managed ToyBox(id=1).",
+                toy1Find.getToybox() == toyboxFind);
+            assertTrue("Assert that Toy(id=2) references the managed ToyBox(id=1).", 
+                toy2Find.getToybox() == toyboxFind);
+
+            em.clear();
+            assertNotNull("Assert em.find(Toy.class, 1) doesn't return null.", em.find(Toy.class, 1));
+            assertNotNull("Assert em.find(Toy.class, 2) doesn't return null.", em.find(Toy.class, 2));
+            assertNotNull("Assert em.find(ToyBox.class, 1) doesn't return null.", em.find(ToyBox.class, 1));
+        } finally {
+            if (em != null) {
+                if (em.getTransaction().isActive())
+                    em.getTransaction().rollback();
+                em.close();
+            }
+        }
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/TestCascadeOneToManyMerge.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/model/Toy.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/model/Toy.java?rev=891120&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/model/Toy.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/model/Toy.java Wed Dec 16 04:17:43 2009
@@ -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.persistence.merge.model;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.Version;
+
+@Entity
+public class Toy {
+    @Id
+    private int id;
+
+    private String toyName;
+
+    @ManyToOne(optional = false, fetch = FetchType.LAZY)
+    private ToyBox toybox;
+
+    @Version
+    private long version;
+
+    public Toy() {
+
+    }
+
+    public Toy(int id) {
+        this.id = id;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public String getToyName() {
+        return toyName;
+    }
+
+    public void setToyName(String toyName) {
+        this.toyName = toyName;
+    }
+
+    public ToyBox getToybox() {
+        return toybox;
+    }
+
+    public void setToybox(ToyBox toybox) {
+        this.toybox = toybox;
+    }
+
+    public long getVersion() {
+        return version;
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/model/Toy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/model/ToyBox.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/model/ToyBox.java?rev=891120&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/model/ToyBox.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/model/ToyBox.java Wed Dec 16 04:17:43 2009
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.persistence.merge.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Basic;
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Version;
+
+@Entity
+public class ToyBox {
+    @Id
+    private int id;
+
+    @Basic
+    private String ownerName;
+
+    @OneToMany(mappedBy = "toybox", cascade = CascadeType.ALL)
+    private List<Toy> toyList;
+
+    @Version
+    private long version;
+
+    public ToyBox() {
+        toyList = new ArrayList<Toy>();
+    }
+
+    public ToyBox(int id) {
+        this.id = id;
+        toyList = new ArrayList<Toy>();
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public String getOwnerName() {
+        return ownerName;
+    }
+
+    public void setOwnerName(String ownerName) {
+        this.ownerName = ownerName;
+    }
+
+    public List<Toy> getToyList() {
+        return toyList;
+    }
+
+    public void setToyList(List<Toy> toyList) {
+        this.toyList = toyList;
+    }
+
+    public long getVersion() {
+        return version;
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/merge/model/ToyBox.java
------------------------------------------------------------------------------
    svn:eol-style = native