/* * Hibernate, Relational Persistence for Idiomatic Java * * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.test.ops; import java.util.List; import org.junit.Test; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.testing.FailureExpected; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; /** * Tests merging multiple detached representations of the same entity (allowed) * where some associations include cascade="delete-orphan" * * @author Gail Badner */ public class MergeMultipleEntityCopiesAllowedOrphanDeleteTest extends BaseCoreFunctionalTestCase { public String[] getMappings() { return new String[] { "ops/HoarderOrphanDelete.hbm.xml" }; } public void configure(Configuration cfg) { super.configure( cfg ); cfg.setProperty( "hibernate.event.merge.entity_copy_observer", "allow" ); } @Test @FailureExpected( jiraKey = "HHH-9240" ) public void testTopLevelUnidirOneToManyBackrefWithNewElement() { Item item1 = new Item(); item1.setName( "item1 name" ); SubItem subItem1 = new SubItem(); subItem1.setName( "subItem1 name" ); item1.getSubItemsBackref().add( subItem1 ); Session s = openSession(); Transaction tx = s.beginTransaction(); s.persist( item1 ); tx.commit(); s.close(); // get another representation of item1 s = openSession(); tx = s.beginTransaction(); Item item1_1 = (Item) s.get( Item.class, item1.getId() ); tx.commit(); s.close(); assertFalse( Hibernate.isInitialized( item1_1.getSubItemsBackref() ) ); Category category = new Category(); category.setName( "category" ); SubItem subItem2 = new SubItem(); subItem2.setName( "subItem2 name" ); item1.getSubItemsBackref().add( subItem2 ); item1.setCategory( category ); category.setExampleItem( item1_1 ); s = openSession(); tx = s.beginTransaction(); // The following will fail due to PropertyValueException because item1 will // be removed from the inverted merge map when the operation cascades to item1_1. Item item1Merged = (Item) s.merge( item1 ); // top-level collection should win assertEquals( 2, item1.getSubItemsBackref().size() ); tx.commit(); s.close(); s = openSession(); tx = s.beginTransaction(); item1 = (Item) s.get( Item.class, item1.getId() ); assertEquals( 2, item1.getSubItemsBackref().size() ); tx.commit(); s.close(); cleanup(); } @Test @FailureExpected( jiraKey = "HHH-9239" ) public void testNestedUnidirOneToManyBackrefWithNewElement() { Item item1 = new Item(); item1.setName( "item1 name" ); SubItem subItem1 = new SubItem(); subItem1.setName( "subItem1 name" ); item1.getSubItemsBackref().add( subItem1 ); Session s = openSession(); Transaction tx = s.beginTransaction(); s.persist( item1 ); tx.commit(); s.close(); // get another representation of item1 s = openSession(); tx = s.beginTransaction(); Item item1_1 = (Item) s.get( Item.class, item1.getId() ); Hibernate.initialize( item1_1.getSubItemsBackref() ); tx.commit(); s.close(); Category category = new Category(); category.setName( "category" ); item1.setCategory( category ); // Add a new SubItem to the Item representation that will be in a nested association. SubItem subItem2 = new SubItem(); subItem2.setName( "subItem2 name" ); item1_1.getSubItemsBackref().add( subItem2 ); category.setExampleItem( item1_1 ); s = openSession(); tx = s.beginTransaction(); Item item1Merged = (Item) s.merge( item1 ); // The resulting collection should contain the added element assertEquals( 2, item1Merged.getSubItemsBackref().size() ); assertEquals( "subItem1 name", item1Merged.getSubItemsBackref().get( 0 ).getName() ); assertEquals( "subItem2 name", item1Merged.getSubItemsBackref().get( 1 ).getName() ); tx.commit(); s.close(); s = openSession(); tx = s.beginTransaction(); item1 = (Item) s.get( Item.class, item1.getId() ); assertEquals( 2, item1.getSubItemsBackref().size() ); assertEquals( "subItem1 name", item1.getSubItemsBackref().get( 0 ).getName() ); assertEquals( "subItem2 name", item1.getSubItemsBackref().get( 1 ).getName() ); tx.commit(); s.close(); cleanup(); } @Test //@FailureExpected( jiraKey = "HHH-9106" ) public void testTopLevelUnidirOneToManyBackrefWithRemovedElement() { Item item1 = new Item(); item1.setName( "item1 name" ); SubItem subItem1 = new SubItem(); subItem1.setName( "subItem1 name" ); item1.getSubItemsBackref().add( subItem1 ); SubItem subItem2 = new SubItem(); subItem2.setName( "subItem2 name" ); item1.getSubItemsBackref().add( subItem2 ); Session s = openSession(); Transaction tx = s.beginTransaction(); s.persist( item1 ); tx.commit(); s.close(); // get another representation of item1 s = openSession(); tx = s.beginTransaction(); Item item1_1 = (Item) s.get( Item.class, item1.getId() ); tx.commit(); s.close(); assertFalse( Hibernate.isInitialized( item1_1.getSubItemsBackref() ) ); Category category = new Category(); category.setName( "category" ); item1.setCategory( category ); category.setExampleItem( item1_1 ); // remove subItem1 from top-level Item item1.getSubItemsBackref().remove( subItem1 ); s = openSession(); tx = s.beginTransaction(); Item item1Merged = (Item) s.merge( item1 ); // element should be removed assertEquals( 1, item1Merged.getSubItemsBackref().size() ); tx.commit(); s.close(); s = openSession(); tx = s.beginTransaction(); item1 = (Item) s.get( Item.class, item1.getId() ); assertEquals( 1, item1.getSubItemsBackref().size() ); // because cascade includes "delete-orphan" the removed SubItem should have been deleted. subItem1 = (SubItem) s.get( SubItem.class, subItem1.getId() ); assertNull( subItem1 ); tx.commit(); cleanup(); } @Test @FailureExpected( jiraKey = "HHH-9239" ) public void testNestedUnidirOneToManyBackrefWithRemovedElement() { Item item1 = new Item(); item1.setName( "item1 name" ); SubItem subItem1 = new SubItem(); subItem1.setName( "subItem1 name" ); item1.getSubItemsBackref().add( subItem1 ); SubItem subItem2 = new SubItem(); subItem2.setName( "subItem2 name" ); item1.getSubItemsBackref().add( subItem2 ); Session s = openSession(); Transaction tx = s.beginTransaction(); s.persist( item1 ); tx.commit(); s.close(); // get another representation of item1 s = openSession(); tx = s.beginTransaction(); Item item1_1 = (Item) s.get( Item.class, item1.getId() ); Hibernate.initialize( item1_1.getSubItemsBackref() ); tx.commit(); s.close(); // remove subItem1 from the nested Item item1_1.getSubItemsBackref().remove( subItem1 ); Category category = new Category(); category.setName( "category" ); item1.setCategory( category ); category.setExampleItem( item1_1 ); s = openSession(); tx = s.beginTransaction(); Item item1Merged = (Item) s.merge( item1 ); // the element should have been removed assertEquals( 1, item1Merged.getSubItemsBackref().size() ); assertTrue( item1Merged.getSubItemsBackref().contains( subItem2 ) ); tx.commit(); s.close(); s = openSession(); tx = s.beginTransaction(); item1 = (Item) s.get( Item.class, item1.getId() ); assertEquals( 1, item1.getSubItemsBackref().size() ); assertTrue( item1.getSubItemsBackref().contains( subItem2 ) ); // because cascade includes "delete-orphan" the removed SubItem should have been deleted. subItem1 = (SubItem) s.get( SubItem.class, subItem1.getId() ); assertNull( subItem1 ); tx.commit(); s.close(); cleanup(); } @Test //@FailureExpected( jiraKey = "HHH-9106" ) public void testTopLevelUnidirOneToManyNoBackrefWithNewElement() { Category category1 = new Category(); category1.setName( "category1 name" ); SubCategory subCategory1 = new SubCategory(); subCategory1.setName( "subCategory1 name" ); category1.getSubCategories().add( subCategory1 ); Session s = openSession(); Transaction tx = s.beginTransaction(); s.persist( category1 ); tx.commit(); s.close(); // get another representation of category1 s = openSession(); tx = s.beginTransaction(); Category category1_1 = (Category) s.get( Category.class, category1.getId() ); tx.commit(); s.close(); assertFalse( Hibernate.isInitialized( category1_1.getSubCategories() ) ); SubCategory subCategory2 = new SubCategory(); subCategory2.setName( "subCategory2 name" ); category1.getSubCategories().add( subCategory2 ); Item item = new Item(); item.setName( "item" ); category1.setExampleItem( item ); item.setCategory( category1_1 ); s = openSession(); tx = s.beginTransaction(); Category category1Merged = (Category) s.merge( category1 ); assertEquals( 2, category1Merged.getSubCategories().size() ); tx.commit(); s.close(); s = openSession(); tx = s.beginTransaction(); category1 = (Category) s.get( Category.class, category1.getId() ); assertEquals( 2, category1.getSubCategories().size() ); tx.commit(); s.close(); cleanup(); } @Test @FailureExpected( jiraKey = "HHH-9239" ) public void testNestedUnidirOneToManyNoBackrefWithNewElement() { Category category1 = new Category(); category1.setName( "category1 name" ); SubCategory subCategory1 = new SubCategory(); subCategory1.setName( "subCategory1 name" ); category1.getSubCategories().add( subCategory1 ); Session s = openSession(); Transaction tx = s.beginTransaction(); s.persist( category1 ); tx.commit(); s.close(); // get another representation of category1 s = openSession(); tx = s.beginTransaction(); Category category1_1 = (Category) s.get( Category.class, category1.getId() ); Hibernate.initialize( category1_1.getSubCategories() ); tx.commit(); s.close(); SubCategory subCategory2 = new SubCategory(); subCategory2.setName( "subCategory2 name" ); category1_1.getSubCategories().add( subCategory2 ); Item item = new Item(); item.setName( "item" ); category1.setExampleItem( item ); item.setCategory( category1_1 ); s = openSession(); tx = s.beginTransaction(); Category category1Merged = (Category) s.merge( category1 ); // new element should be there assertEquals( 2, category1Merged.getSubCategories().size() ); tx.commit(); s.close(); s = openSession(); tx = s.beginTransaction(); category1 = (Category) s.get( Category.class, category1.getId() ); assertEquals( 2, category1.getSubCategories().size() ); tx.commit(); s.close(); cleanup(); } @Test //@FailureExpected( jiraKey = "HHH-9106" ) public void testTopLevelUnidirOneToManyNoBackrefWithRemovedElement() { Category category1 = new Category(); category1.setName( "category1 name" ); SubCategory subCategory1 = new SubCategory(); subCategory1.setName( "subCategory1 name" ); category1.getSubCategories().add( subCategory1 ); SubCategory subCategory2 = new SubCategory(); subCategory2.setName( "subCategory2 name" ); category1.getSubCategories().add( subCategory2 ); Session s = openSession(); Transaction tx = s.beginTransaction(); s.persist( category1 ); tx.commit(); s.close(); // get another representation of category1 s = openSession(); tx = s.beginTransaction(); Category category1_1 = (Category) s.get( Category.class, category1.getId() ); tx.commit(); s.close(); assertFalse( Hibernate.isInitialized( category1_1.getSubCategories() ) ); Item item = new Item(); item.setName( "item" ); category1.setExampleItem( item ); item.setCategory( category1_1 ); category1.getSubCategories().remove( subCategory1 ); s = openSession(); tx = s.beginTransaction(); Category category1Merged = (Category) s.merge( category1 ); assertEquals( 1, category1Merged.getSubCategories().size() ); assertTrue( category1Merged.getSubCategories().contains( subCategory2 ) ); tx.commit(); s.close(); s = openSession(); tx = s.beginTransaction(); category1 = (Category) s.get( Category.class, category1.getId() ); assertEquals( 1, category1.getSubCategories().size() ); assertTrue( category1.getSubCategories().contains( subCategory2 ) ); subCategory1 = (SubCategory) s.get( SubCategory.class, subCategory1.getId() ); assertNull( subCategory1 ); tx.commit(); s.close(); cleanup(); } @Test @FailureExpected( jiraKey = "HHH-9239" ) public void testNestedUnidirOneToManyNoBackrefWithRemovedElement() { Category category1 = new Category(); category1.setName( "category1 name" ); SubCategory subCategory1 = new SubCategory(); subCategory1.setName( "subCategory1 name" ); category1.getSubCategories().add( subCategory1 ); SubCategory subCategory2 = new SubCategory(); subCategory2.setName( "subCategory2 name" ); category1.getSubCategories().add( subCategory2 ); Session s = openSession(); Transaction tx = s.beginTransaction(); s.persist( category1 ); tx.commit(); s.close(); // get another representation of category1 s = openSession(); tx = s.beginTransaction(); Category category1_1 = (Category) s.get( Category.class, category1.getId() ); Hibernate.initialize( category1_1.getSubCategories() ); tx.commit(); s.close(); category1_1.getSubCategories().remove( subCategory2 ); Item item = new Item(); item.setName( "item" ); category1.setExampleItem( item ); item.setCategory( category1_1 ); s = openSession(); tx = s.beginTransaction(); Category category1Merged = (Category) s.merge( category1 ); assertEquals( 1, category1Merged.getSubCategories().size() ); assertTrue( category1Merged.getSubCategories().contains( subCategory2 ) ); tx.commit(); s.close(); s = openSession(); tx = s.beginTransaction(); category1 = (Category) s.get( Category.class, category1.getId() ); assertEquals( 1, category1.getSubCategories().size() ); assertTrue( category1.getSubCategories().contains( subCategory2 ) ); subCategory1 = (SubCategory) s.get( SubCategory.class, subCategory1.getId() ); assertNull( subCategory1 ); tx.commit(); s.close(); cleanup(); } @SuppressWarnings( {"unchecked"}) private void cleanup() { Session s = openSession(); s.beginTransaction(); s.createQuery( "delete from SubItem" ).executeUpdate(); for ( Hoarder hoarder : (List<Hoarder>) s.createQuery( "from Hoarder" ).list() ) { hoarder.getItems().clear(); s.delete( hoarder ); } for ( Category category : (List<Category>) s.createQuery( "from Category" ).list() ) { if ( category.getExampleItem() != null ) { category.setExampleItem( null ); s.delete( category ); } } for ( Item item : (List<Item>) s.createQuery( "from Item" ).list() ) { item.setCategory( null ); s.delete( item ); } s.createQuery( "delete from Item" ).executeUpdate(); s.getTransaction().commit(); s.close(); } }