@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();
  }
  @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 testMergeMultipleEntityCopiesAllowed() {
    Item item1 = new Item();
    item1.setName("item1");

    Hoarder hoarder = new Hoarder();
    hoarder.setName("joe");

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

    // Get another representation of the same Item from a different EntityManager.

    em = getOrCreateEntityManager();
    Item item1_1 = em.find(Item.class, item1.getId());
    em.close();

    // item1_1 and item1_2 are unmodified representations of the same persistent entity.
    assertFalse(item1 == item1_1);
    assertTrue(item1.equals(item1_1));

    // Update hoarder (detached) to references both representations.
    hoarder.getItems().add(item1);
    hoarder.setFavoriteItem(item1_1);

    em = getOrCreateEntityManager();
    em.getTransaction().begin();
    // the merge should succeed because it does not have Category copies.
    // (CustomEntityCopyObserver does not allow Category copies; it does allow Item copies)
    hoarder = em.merge(hoarder);
    assertEquals(1, hoarder.getItems().size());
    assertSame(hoarder.getFavoriteItem(), hoarder.getItems().iterator().next());
    assertEquals(item1.getId(), hoarder.getFavoriteItem().getId());
    assertEquals(item1.getCategory(), hoarder.getFavoriteItem().getCategory());
    em.getTransaction().commit();
    em.close();

    em = getOrCreateEntityManager();
    em.getTransaction().begin();
    hoarder = em.find(Hoarder.class, hoarder.getId());
    assertEquals(1, hoarder.getItems().size());
    assertSame(hoarder.getFavoriteItem(), hoarder.getItems().iterator().next());
    assertEquals(item1.getId(), hoarder.getFavoriteItem().getId());
    assertEquals(item1.getCategory(), hoarder.getFavoriteItem().getCategory());
    em.getTransaction().commit();
    em.close();

    cleanup();
  }
  @Test
  public void testCascadeFromDetachedToGT2DirtyRepresentations() {
    Item item1 = new Item();
    item1.setName("item1");
    Category category1 = new Category();
    category1.setName("category1");
    item1.setCategory(category1);

    Hoarder hoarder = new Hoarder();
    hoarder.setName("joe");

    Session s = openSession();
    Transaction tx = session.beginTransaction();
    s.persist(item1);
    s.persist(hoarder);
    tx.commit();
    s.close();

    // Get another representation of the same Item from a different session.

    s = openSession();
    Item item1_1 = (Item) s.get(Item.class, item1.getId());
    s.close();

    // item1 and item1_1 are unmodified representations of the same persistent entity.
    assertFalse(item1 == item1_1);
    assertTrue(item1.equals(item1_1));

    // Get another representation of the same Item from a different session.

    s = openSession();
    Item item1_2 = (Item) s.get(Item.class, item1.getId());
    s.close();

    // item1_1 and item1_2 are unmodified representations of the same persistent entity.
    assertFalse(item1 == item1_2);
    assertTrue(item1.equals(item1_2));

    item1_1.setName("item1_1");
    item1_2.setName("item1_2");

    // Update hoarder (detached) to references both representations.
    item1.getCategory().setExampleItem(item1_2);
    hoarder.getItems().add(item1);
    hoarder.setFavoriteItem(item1_1);
    hoarder.getFavoriteItem().getCategory();

    s = openSession();
    tx = s.beginTransaction();
    hoarder = (Hoarder) s.merge(hoarder);
    assertEquals(1, hoarder.getItems().size());
    assertSame(hoarder.getFavoriteItem(), hoarder.getItems().iterator().next());
    assertSame(hoarder.getFavoriteItem(), hoarder.getFavoriteItem().getCategory().getExampleItem());
    assertEquals(item1.getId(), hoarder.getFavoriteItem().getId());
    assertEquals(item1.getCategory(), hoarder.getFavoriteItem().getCategory());
    assertEquals(item1.getName(), hoarder.getFavoriteItem().getName());
    tx.commit();
    s.close();

    s = openSession();
    tx = s.beginTransaction();
    hoarder = (Hoarder) s.merge(hoarder);
    assertEquals(1, hoarder.getItems().size());
    assertSame(hoarder.getFavoriteItem(), hoarder.getItems().iterator().next());
    assertSame(hoarder.getFavoriteItem(), hoarder.getFavoriteItem().getCategory().getExampleItem());
    assertEquals(item1.getId(), hoarder.getFavoriteItem().getId());
    assertEquals(item1.getCategory(), hoarder.getFavoriteItem().getCategory());
    tx.commit();
    s.close();

    cleanup();
  }