From 54d4d0d07d5405670c84823ee2701f497f384538 Mon Sep 17 00:00:00 2001 From: Jeremy Bauer Date: Fri, 31 Oct 2008 18:39:16 +0000 Subject: [PATCH] OPENJPA-755 Update to SingleFieldManager to permit detached related entities on a merge with cascade persist. Committing for Dinkar Rao. git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@709527 13f79535-47bb-0310-9956-ffa450edef68 --- .../openjpa/kernel/SingleFieldManager.java | 7 +- .../TestDetachedEntityCascadePersist.java | 74 ++++++++++++++++++ .../detachment/model/DMCustomer.java | 77 +++++++++++++++++++ .../detachment/model/DMCustomerInventory.java | 75 ++++++++++++++++++ .../persistence/detachment/model/DMItem.java | 51 ++++++++++++ 5 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/TestDetachedEntityCascadePersist.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/model/DMCustomer.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/model/DMCustomerInventory.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/model/DMItem.java diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SingleFieldManager.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SingleFieldManager.java index 9bf1fc0fe..b505fd89e 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SingleFieldManager.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SingleFieldManager.java @@ -743,7 +743,8 @@ class SingleFieldManager if (obj == null) return; - OpenJPAStateManager sm; + OpenJPAStateManager sm; + if (vmd.getCascadePersist() == ValueMetaData.CASCADE_NONE) { if (!_broker.isDetachedNew() && _broker.isDetached(obj)) return; // allow but ignore @@ -754,6 +755,10 @@ class SingleFieldManager _loc.get("cant-cascade-persist", vmd)) .setFailedObject(obj); } else { + if (vmd.getCascadePersist() == ValueMetaData.CASCADE_IMMEDIATE) { + if (!_broker.isDetachedNew() && _broker.isDetached(obj)) + return; // allow but ignore + } sm = _broker.getStateManager(obj); if (sm == null || !sm.isProvisional()) { sm = _broker.persist(obj, null, true, call); diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/TestDetachedEntityCascadePersist.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/TestDetachedEntityCascadePersist.java new file mode 100644 index 000000000..c176c9d90 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/TestDetachedEntityCascadePersist.java @@ -0,0 +1,74 @@ +/* + * 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.detachment; + +import javax.persistence.EntityManager; + +import org.apache.openjpa.persistence.detachment.model.DMCustomer; +import org.apache.openjpa.persistence.detachment.model.DMCustomerInventory; +import org.apache.openjpa.persistence.detachment.model.DMItem; +import org.apache.openjpa.persistence.test.SingleEMFTestCase; + +public class TestDetachedEntityCascadePersist extends SingleEMFTestCase { + + public void setUp() { + setUp( + CLEAR_TABLES, + DMCustomer.class, + DMItem.class, + DMCustomerInventory.class + ); + } + + public void testDetachedEntityCascadePersist() { + // Persist an item for finding later + EntityManager em = emf.createEntityManager(); + DMItem item = new DMItem(); + item.setName("openjpa"); + item.setPrice(0.0); + em.getTransaction().begin(); + em.persist(item); + // Persist a customer for finding later + DMCustomer customer = new DMCustomer(); + customer.setFirstName("Open"); + customer.setLastName("JPA"); + em.persist(customer); + em.getTransaction().commit(); + em.close(); + + em = emf.createEntityManager(); + DMItem itemDetached = em.find(DMItem.class, item.getId()); + em.close(); + em = emf.createEntityManager(); + DMCustomer customer2 = em.find(DMCustomer.class, customer.getId()); + DMCustomerInventory customerInventory = new DMCustomerInventory(); + customerInventory.setCustomer(customer2); + customerInventory.setItem(itemDetached); + customerInventory.setQuantity(20); + customer2.getCustomerInventories().add(customerInventory); + em.getTransaction().begin(); + em.merge(customer2); + // At this point, itemDetached is still detached. + // The following commit causes a persist on CustomerInventory, + // which leads to a cascade-persist on the detached item. + // This cascade-persist on a detached item should be ignored, + // instead of a EntityExistsException being thrown + em.getTransaction().commit(); + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/model/DMCustomer.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/model/DMCustomer.java new file mode 100644 index 000000000..f0992ac63 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/model/DMCustomer.java @@ -0,0 +1,77 @@ +/* + * 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.detachment.model; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +@Entity +public class DMCustomer { + + private static long idCounter = System.currentTimeMillis(); + @Id private long id = idCounter++; + private String firstName; + private String lastName; + + @OneToMany(mappedBy="customer", + fetch=FetchType.EAGER, + cascade=CascadeType.ALL) + private List customerInventories = new ArrayList(); + + public DMCustomer() { + } + + public long getId() { + return id; + } + + public void setId(long 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 List getCustomerInventories() { + return customerInventories; + } + + public void setCustomerInventories(List customerInventories) { + this.customerInventories = customerInventories; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/model/DMCustomerInventory.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/model/DMCustomerInventory.java new file mode 100644 index 000000000..83d1d75e2 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/model/DMCustomerInventory.java @@ -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.detachment.model; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; + +@Entity +public class DMCustomerInventory { + private static long idCounter = System.currentTimeMillis(); + @Id private long id = idCounter++; + + @ManyToOne(cascade=CascadeType.ALL) + @JoinColumn(name = "CI_ITEMID") + private DMItem item; + private int quantity; + + @ManyToOne(cascade=CascadeType.MERGE) + @JoinColumn(name="CI_CUSTOMERID") + private DMCustomer customer; + + public DMCustomerInventory() { + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public DMItem getItem() { + return item; + } + + public void setItem(DMItem item) { + this.item = item; + } + + public int getQuantity() { + return quantity; + } + + public void setQuantity(int quantity) { + this.quantity = quantity; + } + + public DMCustomer getCustomer() { + return customer; + } + + public void setCustomer(DMCustomer customer) { + this.customer = customer; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/model/DMItem.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/model/DMItem.java new file mode 100644 index 000000000..c13c962ed --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detachment/model/DMItem.java @@ -0,0 +1,51 @@ +/* + * 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.detachment.model; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class DMItem { + private static long idCounter = System.currentTimeMillis(); + @Id private long id = idCounter++; + + private String name; + private double price; + + + public long getId() { + return id; + } + public void setId(long id) { + this.id = id; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public double getPrice() { + return price; + } + public void setPrice(double price) { + this.price = price; + } +}