blob: d72ab758283368e23ce78548b993fa82bc50ca19 [file] [log] [blame]
/*
* 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 java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.openjpa.conf.Compatibility;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.MetaDataRepository;
import org.apache.openjpa.meta.ValueMetaData;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
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;
/**
* Tests detachment behavior according to JPA 2.0 Specification. The primary
* changes in detachment behavior from the existing OpenJPA behavior are
* i. detach(x) does not flush if x is dirty
* ii. detach(x) removes x from persistence context
* iii. detach(x) propagates via CascadeType.DETACH. It is not clear how that
* impacts the detach graph. So currently, detach graph is same as 'loaded'.
*
* The test uses a 'domain model' with following cascade relation
*
* ALL PERSIST, MERGE, REFRESH
* Customer --------> Inventory ----------------------> Item
* <-------
* MERGE
*
* @author Pinaki Poddar
*
*/
public class TestDetach extends SingleEMFTestCase {
OpenJPAEntityManager em;
DMCustomer root;
@Override
public void setUp() {
super.setUp(DMCustomer.class, DMCustomerInventory.class, DMItem.class,
CLEAR_TABLES);
Compatibility compat =
emf.getConfiguration().getCompatibilityInstance();
compat.setCopyOnDetach(false);
compat.setFlushBeforeDetach(false);
em = emf.createEntityManager();
root = createData();
}
public void testDetachCascadeIsSet() {
MetaDataRepository repos = emf.getConfiguration()
.getMetaDataRepositoryInstance();
ClassMetaData meta = repos.getCachedMetaData(DMCustomer.class);
assertEquals(ValueMetaData.CASCADE_NONE,
meta.getField("firstName").getCascadeDetach());
assertEquals(ValueMetaData.CASCADE_IMMEDIATE, meta.getField(
"customerInventories").getElement().getCascadeDetach());
meta = repos.getCachedMetaData(DMCustomerInventory.class);
assertEquals(ValueMetaData.CASCADE_NONE,
meta.getField("customer").getCascadeDetach());
assertEquals(ValueMetaData.CASCADE_NONE,
meta.getField("item").getCascadeDetach());
}
public void testDetachRemovesEntityAndCascadedRelationFromContext() {
em.getTransaction().begin();
DMCustomer pc = em.find(DMCustomer.class, root.getId());
List<DMCustomerInventory> inventories = pc.getCustomerInventories();
DMItem item = inventories.get(0).getItem();
assertNotDetached(pc);
for (DMCustomerInventory i : inventories) assertNotDetached(i);
assertNotDetached(item);
em.detach(pc);
assertDetached(pc);
for (DMCustomerInventory i : inventories) assertDetached(i);
em.getTransaction().rollback();
assertNotNull(pc.getFirstName());
}
public void testDetachingDirtyEntityDoesNotImplicitlyFlush() {
em.getTransaction().begin();
DMCustomer pc = em.find(DMCustomer.class, root.getId());
String original = pc.getLastName();
pc.setLastName("Changed That Should not be Saved");
em.detach(pc);
em.getTransaction().commit();
DMCustomer pc2 = em.find(DMCustomer.class, root.getId());
assertNotNull(pc2);
assertEquals(original, pc2.getLastName());
}
public void testDetachingNewEntityIsIgnored() {
em.getTransaction().begin();
DMCustomer pc = em.find(DMCustomer.class, root.getId());
List<DMCustomerInventory> inventories = pc.getCustomerInventories();
DMCustomer newPC = new DMCustomer();
newPC.setCustomerInventories(inventories);
for (DMCustomerInventory inventory : inventories)
inventory.setCustomer(newPC);
em.detach(newPC);
for (DMCustomerInventory inventory : inventories) {
assertNotDetached(inventory);
}
em.getTransaction().rollback();
}
public void testDetachingDetachedEntityIsIgnored() {
em.getTransaction().begin();
DMCustomer pc = em.find(DMCustomer.class, root.getId());
List<DMCustomerInventory> inventories = pc.getCustomerInventories();
em.detach(pc);
DMCustomer detached = pc;
assertDetached(detached);
for (DMCustomerInventory inventory : inventories) {
assertDetached(inventory);
}
List<DMCustomerInventory> newInventories =
new ArrayList<>(inventories);
DMCustomerInventory newInventory = new DMCustomerInventory();
newInventory.setCustomer(detached);
newInventories.add(newInventory);
detached.setCustomerInventories(newInventories);
em.persist(newInventory);
assertNotDetached(newInventory);
em.detach(detached);
assertDetached(detached);
assertEquals(inventories.size()+1, newInventories.size());
for (DMCustomerInventory inventory : newInventories) {
if (inventory == newInventory)
assertNotDetached(inventory);
else
assertDetached(inventory);
}
em.getTransaction().rollback();
}
public void testFlushingBeforeDetachingSavesChange() {
}
public void testManagedEntityContinuesToReferDetachedEntities() {
em.getTransaction().begin();
DMCustomer pc = em.find(DMCustomer.class, root.getId());
List<DMCustomerInventory> inventories = pc.getCustomerInventories();
DMItem item = inventories.get(1).getItem();
em.detach(inventories.get(0));
DMCustomerInventory attached0 = inventories.get(0);
DMCustomerInventory attached1 = inventories.get(1);
assertSame(pc.getCustomerInventories().get(0), attached0);
assertSame(pc.getCustomerInventories().get(1), attached1);
em.getTransaction().rollback();
}
DMCustomer createData() {
DMItem item1 = new DMItem();
DMItem item2 = new DMItem();
item1.setName("item-1"); item1.setPrice(100.0);
item2.setName("item-2"); item2.setPrice(200.0);
DMCustomerInventory inventory1 = new DMCustomerInventory();
DMCustomerInventory inventory2 = new DMCustomerInventory();
inventory1.setItem(item1); inventory1.setQuantity(10);
inventory2.setItem(item2); inventory2.setQuantity(20);
DMCustomer customer = new DMCustomer();
customer.setFirstName("Detached"); customer.setLastName("Customer");
customer.setCustomerInventories(Arrays.asList(
new DMCustomerInventory[]{inventory1,inventory2}));
inventory1.setCustomer(customer);
inventory2.setCustomer(customer);
em.getTransaction().begin();
em.persist(customer);
em.getTransaction().commit();
em.clear();
return customer;
}
void assertDetached(Object pc) {
assertTrue(pc + " should be detached", em.isDetached(pc));
assertFalse(pc + " should not be in cache", em.contains(pc));
}
void assertNotDetached(Object pc) {
assertFalse(pc + " should not be detached", em.isDetached(pc));
assertTrue(pc + " should be in cache", em.contains(pc));
}
}