@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()) {
      Item exampleItem = category.getExampleItem();
      if (exampleItem != null) {
        category.setExampleItem(null);
        exampleItem.setCategory(null);
        s.delete(category);
        s.delete(exampleItem);
      }
    }

    for (Item item : (List<Item>) s.createQuery("from Item").list()) {
      Category category = item.getCategory();
      item.setCategory(null);
      if (category != null) {
        category.setExampleItem(null);
      }
      s.delete(item);
    }

    s.createQuery("delete from Item").executeUpdate();

    s.getTransaction().commit();
    s.close();
  }
  @Test
  public void testMergeMultipleEntityCopiesAllowedAndDisallowed() {
    Item item1 = new Item();
    item1.setName("item1 name");
    Category category = new Category();
    category.setName("category");
    item1.setCategory(category);
    category.setExampleItem(item1);

    EntityManager em = getOrCreateEntityManager();
    em.getTransaction().begin();
    em.persist(item1);
    em.getTransaction().commit();
    em.close();

    // get another representation of item1
    em = getOrCreateEntityManager();
    em.getTransaction().begin();
    Item item1_1 = em.find(Item.class, item1.getId());
    // make sure item1_1.category is initialized
    Hibernate.initialize(item1_1.getCategory());
    em.getTransaction().commit();
    em.close();

    em = getOrCreateEntityManager();
    em.getTransaction().begin();
    Item item1Merged = em.merge(item1);

    // make sure item1Merged.category is also managed
    Hibernate.initialize(item1Merged.getCategory());

    item1Merged.setCategory(category);
    category.setExampleItem(item1_1);

    // now item1Merged is managed and it has a nested detached item
    // and there is  multiple managed/detached Category objects
    try {
      // the following should fail because multiple copies of Category objects is not allowed by
      // CustomEntityCopyObserver
      em.merge(item1Merged);
      fail(
          "should have failed because CustomEntityCopyObserver does not allow multiple copies of a Category. ");
    } catch (IllegalStateException ex) {
      // expected
    } finally {
      em.getTransaction().rollback();
    }
    em.close();

    em = getOrCreateEntityManager();
    em.getTransaction().begin();
    item1 = em.find(Item.class, item1.getId());
    assertEquals(category.getName(), item1.getCategory().getName());
    assertSame(item1, item1.getCategory().getExampleItem());
    em.getTransaction().commit();
    em.close();

    cleanup();
  }
  @Test
  public void testTopLevelManyToOneChangedToNewEntity() {
    Item item1 = new Item();
    item1.setName("item1 name");
    Category category = new Category();
    category.setName("category");

    item1.setCategory(category);
    category.setExampleItem(item1);

    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();

    // change many-to-one in top level to be a new (transient)
    Category categoryNewer = new Category();
    categoryNewer.setName("newer category");
    item1.setCategory(categoryNewer);

    // put the other representation in categoryNewer
    categoryNewer.setExampleItem(item1_1);

    s = openSession();
    tx = s.beginTransaction();
    Item item1Merged = (Item) s.merge(item1);
    // the many-to-one from the top level item will win.
    assertEquals(categoryNewer.getName(), item1Merged.getCategory().getName());
    assertSame(item1Merged, item1Merged.getCategory().getExampleItem());
    tx.commit();
    s.close();

    s = openSession();
    tx = s.beginTransaction();
    item1 = (Item) s.get(Item.class, item1.getId());
    assertEquals(categoryNewer.getName(), item1.getCategory().getName());
    assertSame(item1, item1.getCategory().getExampleItem());
    // make sure original category is still there
    Category categoryQueried =
        (Category) s.createQuery("from Category c where c.name='category'").uniqueResult();
    assertNotNull(categoryQueried);
    // make sure original category has the same item.
    assertSame(item1, categoryQueried.getExampleItem());
    // set exampleItem to null to avoid constraint violation on cleanup.
    categoryQueried.setExampleItem(null);
    tx.commit();
    s.close();

    cleanup();
  }
  @SuppressWarnings({"unchecked"})
  private void cleanup() {
    EntityManager em = getOrCreateEntityManager();
    em.getTransaction().begin();

    for (Hoarder hoarder : (List<Hoarder>) em.createQuery("from Hoarder").getResultList()) {
      hoarder.getItems().clear();
      em.remove(hoarder);
    }

    for (Category category : (List<Category>) em.createQuery("from Category").getResultList()) {
      if (category.getExampleItem() != null) {
        category.setExampleItem(null);
        em.remove(category);
      }
    }

    for (Item item : (List<Item>) em.createQuery("from Item").getResultList()) {
      item.setCategory(null);
      em.remove(item);
    }

    em.createQuery("delete from Item").executeUpdate();

    em.getTransaction().commit();
    em.close();
  }
  @Test
  public void testTopLevelManyToOneManagedNestedIsDetached() {
    Item item1 = new Item();
    item1.setName("item1 name");
    Category category = new Category();
    category.setName("category");
    item1.setCategory(category);
    category.setExampleItem(item1);

    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();

    s = openSession();
    tx = s.beginTransaction();
    Item item1Merged = (Item) s.merge(item1);

    item1Merged.setCategory(category);
    category.setExampleItem(item1_1);

    // now item1Merged is managed and it has a nested detached item
    s.merge(item1Merged);
    assertEquals(category.getName(), item1Merged.getCategory().getName());
    assertSame(item1Merged, item1Merged.getCategory().getExampleItem());
    tx.commit();
    s.close();

    s = openSession();
    tx = s.beginTransaction();
    item1 = (Item) s.get(Item.class, item1.getId());
    assertEquals(category.getName(), item1.getCategory().getName());
    assertSame(item1, item1.getCategory().getExampleItem());
    tx.commit();
    s.close();

    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 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);
    // entity should have been 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());
    subItem1 = (SubItem) s.get(SubItem.class, subItem1.getId());
    // cascade does not include delete-orphan, so subItem1 should still be persistent.
    assertNotNull(subItem1);
    tx.commit();

    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));
    // cascade does not include delete-orphan, so subCategory1 should still be persistent.
    subCategory1 = (SubCategory) s.get(SubCategory.class, subCategory1.getId());
    assertNotNull(subCategory1);
    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-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 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();
  }
  @Test
  public void testNestedManyToOneChangedToNewEntity() {
    Item item1 = new Item();
    item1.setName("item1 name");
    Category category = new Category();
    category.setName("category");

    item1.setCategory(category);
    category.setExampleItem(item1);

    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();

    // change many-to-one in nested entity to a new (transient) value
    Category categoryNew = new Category();
    categoryNew.setName("new category");
    item1_1.setCategory(categoryNew);
    item1.getCategory().setExampleItem(item1_1);

    s = openSession();
    tx = s.beginTransaction();
    Item item1Merged = (Item) s.merge(item1);
    // the many-to-one from the top level item will win.
    assertEquals(category.getName(), item1Merged.getCategory().getName());
    assertSame(item1Merged, item1Merged.getCategory().getExampleItem());
    tx.commit();
    s.close();

    s = openSession();
    tx = s.beginTransaction();
    item1 = (Item) s.get(Item.class, item1.getId());
    assertEquals(category.getName(), item1.getCategory().getName());
    assertSame(item1, item1.getCategory().getExampleItem());
    // make sure new category got persisted
    Category categoryQueried =
        (Category) s.createQuery("from Category c where c.name='new category'").uniqueResult();
    assertNotNull(categoryQueried);
    tx.commit();
    s.close();

    cleanup();
  }
  @Test
  public void testTopLevelEntityNewerThanNested() {
    Item item = new Item();
    item.setName("item");

    Category category = new Category();
    category.setName("category");

    Session s = openSession();
    Transaction tx = s.beginTransaction();
    s.persist(item);
    s.persist(category);
    tx.commit();
    s.close();

    // Get the Category from a different session.
    s = openSession();
    tx = s.beginTransaction();
    Category category1_2 = (Category) s.get(Category.class, category.getId());
    tx.commit();
    s.close();

    // Get and update the same Category.
    s = openSession();
    tx = s.beginTransaction();
    Category category1_1 = (Category) s.get(Category.class, category.getId());
    category1_1.setName("new name");
    tx.commit();
    s.close();

    assertTrue(category1_2.getVersion() < category1_1.getVersion());

    category1_1.setExampleItem(item);
    item.setCategory(category1_2);

    s = openSession();
    tx = s.beginTransaction();
    try {
      // representation merged at top level is newer than nested representation.
      category1_1 = (Category) s.merge(category1_1);
      fail("should have failed because one representation is an older version.");
    } catch (StaleObjectStateException ex) {
      // expected
    } finally {
      tx.rollback();
      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
  public void testNestedManyToOneChangedToNull() {
    Item item1 = new Item();
    item1.setName("item1 name");
    Category category = new Category();
    category.setName("category");

    item1.setCategory(category);
    category.setExampleItem(item1);

    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();

    // change many-to-one in nested entity to null.
    item1_1.setCategory(null);
    item1.getCategory().setExampleItem(item1_1);

    s = openSession();
    tx = s.beginTransaction();
    Item item1Merged = (Item) s.merge(item1);
    // the many-to-one from the top level item will win.
    assertEquals(category.getName(), item1Merged.getCategory().getName());
    assertSame(item1Merged, item1Merged.getCategory().getExampleItem());
    tx.commit();
    s.close();

    s = openSession();
    tx = s.beginTransaction();
    item1 = (Item) s.get(Item.class, item1.getId());
    assertEquals(category.getName(), item1.getCategory().getName());
    assertSame(item1, item1.getCategory().getExampleItem());
    tx.commit();
    s.close();

    cleanup();
  }
  @Test
  public void testNestedDiffBasicProperty() {
    Item item1 = new Item();
    item1.setName("item1 name");
    Category category = new Category();
    category.setName("category");

    item1.setCategory(category);
    category.setExampleItem(item1);

    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();

    // change basic property of nested entity
    item1_1.setName("item1_1 name");

    // change the nested Item to be the copy with the new name
    item1.getCategory().setExampleItem(item1_1);

    s = openSession();
    tx = s.beginTransaction();
    Item item1Merged = (Item) s.merge(item1);
    // the name from the top level item will win.
    assertEquals(item1.getName(), item1Merged.getName());
    tx.commit();
    s.close();

    s = openSession();
    tx = s.beginTransaction();
    Item item1Get = (Item) s.get(Item.class, item1.getId());
    assertEquals(item1.getName(), item1Get.getName());
    tx.commit();
    s.close();

    cleanup();
  }
  @Test
  public void testTopValueCollectionWithChangedElements() {
    Item item1 = new Item();
    item1.setName("item1 name");
    Category category = new Category();
    category.setName("category");
    item1.getColors().add("red");

    item1.setCategory(category);
    category.setExampleItem(item1);

    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();

    // add an element to collection in nested entity
    item1.getColors().add("blue");
    item1.getCategory().setExampleItem(item1_1);

    s = openSession();
    tx = s.beginTransaction();
    Item item1Merged = (Item) s.merge(item1);
    // the collection from the top level item will win.
    assertEquals(2, item1Merged.getColors().size());
    assertTrue(item1Merged.getColors().contains("red"));
    assertTrue(item1Merged.getColors().contains("blue"));
    tx.commit();
    s.close();

    s = openSession();
    tx = s.beginTransaction();
    item1 = (Item) s.get(Item.class, item1.getId());
    assertEquals(2, item1.getColors().size());
    assertTrue(item1.getColors().contains("red"));
    assertTrue(item1.getColors().contains("blue"));
    Hibernate.initialize(item1.getCategory());
    tx.commit();
    s.close();

    // get another representation of item1
    s = openSession();
    tx = s.beginTransaction();
    item1_1 = (Item) s.get(Item.class, item1.getId());
    tx.commit();
    s.close();

    // remove the existing elements from collection in nested entity
    item1.getColors().clear();
    item1.getCategory().setExampleItem(item1_1);

    s = openSession();
    tx = s.beginTransaction();
    item1Merged = (Item) s.merge(item1);
    // the collection from the top level item will win.
    assertTrue(item1Merged.getColors().isEmpty());
    tx.commit();
    s.close();

    s = openSession();
    tx = s.beginTransaction();
    item1 = (Item) s.get(Item.class, item1.getId());
    assertTrue(item1.getColors().isEmpty());
    tx.commit();
    s.close();

    cleanup();
  }