@Test
  @SuppressWarnings({"UnusedAssignment", "UnnecessaryBoxing"})
  public void testSaveOrUpdateManaged() throws Exception {
    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    Session s = openSession();
    NumberedNode root = new NumberedNode("root");
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (NumberedNode) getOldToNewEntityRefMap().get(root);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    root = (NumberedNode) s.get(NumberedNode.class, root.getId());
    NumberedNode child = new NumberedNode("child");
    root.addChild(child);
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (NumberedNode) getOldToNewEntityRefMap().get(root);
    assertNull(getOldToNewEntityRefMap().get(child));
    s.flush();
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (NumberedNode) getOldToNewEntityRefMap().get(root);
    child = (NumberedNode) getOldToNewEntityRefMap().get(child);
    child = (NumberedNode) root.getChildren().iterator().next();
    assertTrue(s.contains(child));
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (NumberedNode) getOldToNewEntityRefMap().get(root);
    child = (NumberedNode) getOldToNewEntityRefMap().get(child);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    assertTrue(root.getChildren().contains(child));
    assertEquals(root.getChildren().size(), 1);

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    assertEquals(
        Long.valueOf(2),
        s.createCriteria(NumberedNode.class).setProjection(Projections.rowCount()).uniqueResult());
    s.delete(root);
    s.delete(child);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
  }
  @Test
  @SuppressWarnings({"UnusedAssignment"})
  public void testSaveOrUpdateTreeWithGeneratedId() throws Exception {
    clearCounts();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    Session s = openSession();
    NumberedNode root = new NumberedNode("root");
    NumberedNode child = new NumberedNode("child");
    root.addChild(child);
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (NumberedNode) getOldToNewEntityRefMap().get(root);
    child = (NumberedNode) getOldToNewEntityRefMap().get(child);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    assertInsertCount(2);
    clearCounts();

    root.setDescription("The root node");
    child.setDescription("The child node");

    NumberedNode secondChild = new NumberedNode("second child");

    root.addChild(secondChild);

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    assertInsertCount(1);
    assertUpdateCount(2);

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    s.createQuery("delete from NumberedNode where parent is not null").executeUpdate();
    s.createQuery("delete from NumberedNode").executeUpdate();
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
  }
  @Test
  @SuppressWarnings({"UnusedAssignment"})
  public void testSaveOrUpdateDeepTree() throws Exception {
    clearCounts();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    Session s = openSession();
    Node root = new Node("root");
    Node child = new Node("child");
    Node grandchild = new Node("grandchild");
    root.addChild(child);
    child.addChild(grandchild);
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (Node) getOldToNewEntityRefMap().get(root);
    child = (Node) getOldToNewEntityRefMap().get(child);
    grandchild = (Node) getOldToNewEntityRefMap().get(grandchild);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    assertInsertCount(3);
    assertUpdateCount(0);
    clearCounts();

    grandchild.setDescription("the grand child");
    Node grandchild2 = new Node("grandchild2");
    child.addChild(grandchild2);

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (Node) getOldToNewEntityRefMap().get(root);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    assertInsertCount(1);
    assertUpdateCount(1);
    clearCounts();

    Node child2 = new Node("child2");
    Node grandchild3 = new Node("grandchild3");
    child2.addChild(grandchild3);
    root.addChild(child2);

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    assertInsertCount(2);
    assertUpdateCount(0);
    clearCounts();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    s.delete(grandchild);
    s.delete(grandchild2);
    s.delete(grandchild3);
    s.delete(child);
    s.delete(child2);
    s.delete(root);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
  }
  @Test
  @SuppressWarnings({"UnusedAssignment"})
  public void testEvictThenSaveOrUpdate() throws Exception {
    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    Session s = openSession();
    Node parent = new Node("1:parent");
    Node child = new Node("2:child");
    Node grandchild = new Node("3:grandchild");
    parent.addChild(child);
    child.addChild(grandchild);
    s.saveOrUpdate(parent);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    Session s1 = openSession();
    child = (Node) s1.load(Node.class, "2:child");
    s1 = applyNonFlushedChangesToNewSessionCloseOldSession(s1);
    child = (Node) getOldToNewEntityRefMap().get(child);
    assertTrue(s1.contains(child));
    assertFalse(Hibernate.isInitialized(child));
    assertTrue(s1.contains(child.getParent()));
    assertTrue(Hibernate.isInitialized(child));
    assertFalse(Hibernate.isInitialized(child.getChildren()));
    assertFalse(Hibernate.isInitialized(child.getParent()));
    assertTrue(s1.contains(child));
    s1 = applyNonFlushedChangesToNewSessionCloseOldSession(s1);
    // child is an initialized proxy; after serialization, it is
    // the proxy is replaced by its implementation
    // TODO: find out if this is how this should work...
    child =
        (Node)
            getOldToNewEntityRefMap()
                .get(((HibernateProxy) child).getHibernateLazyInitializer().getImplementation());
    s1.evict(child);
    assertFalse(s1.contains(child));
    assertTrue(s1.contains(child.getParent()));

    javax.transaction.Transaction tx1 =
        TestingJtaBootstrap.INSTANCE.getTransactionManager().suspend();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    Session s2 = openSession();
    try {
      s2.getTransaction().begin();
      s2.saveOrUpdate(child);
      fail();
    } catch (HibernateException ex) {
      // expected because parent is connected to s1
    } finally {
      TestingJtaBootstrap.INSTANCE.getTransactionManager().rollback();
    }

    s1.evict(child.getParent());
    assertFalse(s1.contains(child.getParent()));

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s2 = openSession();
    s2.saveOrUpdate(child);
    s2 = applyNonFlushedChangesToNewSessionCloseOldSession(s2);
    child = (Node) getOldToNewEntityRefMap().get(child);
    assertTrue(s2.contains(child));
    assertFalse(s1.contains(child));
    assertTrue(s2.contains(child.getParent()));
    assertFalse(s1.contains(child.getParent()));
    assertFalse(Hibernate.isInitialized(child.getChildren()));
    assertFalse(Hibernate.isInitialized(child.getParent()));
    assertEquals(1, child.getChildren().size());
    assertEquals("1:parent", child.getParent().getName());
    assertTrue(Hibernate.isInitialized(child.getChildren()));
    assertFalse(Hibernate.isInitialized(child.getParent()));
    assertNull(child.getParent().getDescription());
    assertTrue(Hibernate.isInitialized(child.getParent()));
    s1 = applyNonFlushedChangesToNewSessionCloseOldSession(s1);
    s2 = applyNonFlushedChangesToNewSessionCloseOldSession(s2);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().resume(tx1);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
    //		tx1.commit();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    s.delete(s.get(Node.class, "3:grandchild"));
    s.delete(s.get(Node.class, "2:child"));
    s.delete(s.get(Node.class, "1:parent"));
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
  }
  @Test
  @SuppressWarnings({"UnusedAssignment", "UnnecessaryBoxing"})
  public void testSaveOrUpdateGotWithMutableProp() throws Exception {
    clearCounts();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    Session s = openSession();
    Node root = new Node("root");
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (Node) getOldToNewEntityRefMap().get(root);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    assertInsertCount(1);
    assertUpdateCount(0);
    clearCounts();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (Node) getOldToNewEntityRefMap().get(root);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    assertInsertCount(0);
    assertUpdateCount(0);

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    root = (Node) s.get(Node.class, "root");
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (Node) getOldToNewEntityRefMap().get(root);
    Hibernate.initialize(root.getChildren());
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (Node) getOldToNewEntityRefMap().get(root);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    clearCounts();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    Node child = new Node("child");
    root.addChild(child);
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (Node) getOldToNewEntityRefMap().get(root);
    child = (Node) root.getChildren().iterator().next();
    assertTrue(s.contains(child));
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (Node) getOldToNewEntityRefMap().get(root);
    child = (Node) getOldToNewEntityRefMap().get(child);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    assertInsertCount(1);
    // assertUpdateCount( 1 ); //note: will fail here if no second-level cache

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    assertEquals(
        Long.valueOf(2),
        s.createCriteria(Node.class).setProjection(Projections.rowCount()).uniqueResult());
    s.delete(root);
    s.delete(child);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
  }
  @Test
  @SuppressWarnings({"UnusedAssignment", "UnnecessaryBoxing"})
  public void testSaveOrUpdateGot() throws Exception {
    boolean instrumented = FieldInterceptionHelper.isInstrumented(new NumberedNode());

    clearCounts();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    Session s = openSession();
    NumberedNode root = new NumberedNode("root");
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (NumberedNode) getOldToNewEntityRefMap().get(root);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    assertInsertCount(1);
    assertUpdateCount(0);
    clearCounts();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (NumberedNode) getOldToNewEntityRefMap().get(root);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    assertInsertCount(0);
    assertUpdateCount(instrumented ? 0 : 1);

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    root = (NumberedNode) s.get(NumberedNode.class, Long.valueOf(root.getId()));
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (NumberedNode) getOldToNewEntityRefMap().get(root);
    Hibernate.initialize(root.getChildren());
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (NumberedNode) getOldToNewEntityRefMap().get(root);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    clearCounts();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    NumberedNode child = new NumberedNode("child");
    root.addChild(child);
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (NumberedNode) getOldToNewEntityRefMap().get(root);
    assertTrue(Hibernate.isInitialized(root.getChildren()));
    child = (NumberedNode) root.getChildren().iterator().next();
    assertTrue(s.contains(child));
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    assertInsertCount(1);
    assertUpdateCount(instrumented ? 0 : 1);

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    assertEquals(
        s.createCriteria(NumberedNode.class).setProjection(Projections.rowCount()).uniqueResult(),
        new Long(2));
    s.delete(root);
    s.delete(child);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
  }
  @Test
  @SuppressWarnings({"UnusedAssignment"})
  public void testSaveOrUpdateDeepTreeWithGeneratedId() throws Exception {
    boolean instrumented = FieldInterceptionHelper.isInstrumented(new NumberedNode());
    clearCounts();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    Session s = openSession();
    NumberedNode root = new NumberedNode("root");
    NumberedNode child = new NumberedNode("child");
    NumberedNode grandchild = new NumberedNode("grandchild");
    root.addChild(child);
    child.addChild(grandchild);
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (NumberedNode) getOldToNewEntityRefMap().get(root);
    child = (NumberedNode) getOldToNewEntityRefMap().get(child);
    grandchild = (NumberedNode) getOldToNewEntityRefMap().get(grandchild);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    assertInsertCount(3);
    assertUpdateCount(0);
    clearCounts();

    child = (NumberedNode) root.getChildren().iterator().next();
    grandchild = (NumberedNode) child.getChildren().iterator().next();
    grandchild.setDescription("the grand child");
    NumberedNode grandchild2 = new NumberedNode("grandchild2");
    child.addChild(grandchild2);

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    root = (NumberedNode) getOldToNewEntityRefMap().get(root);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    assertInsertCount(1);
    assertUpdateCount(instrumented ? 1 : 3);
    clearCounts();

    NumberedNode child2 = new NumberedNode("child2");
    NumberedNode grandchild3 = new NumberedNode("grandchild3");
    child2.addChild(grandchild3);
    root.addChild(child2);

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    s.saveOrUpdate(root);
    s = applyNonFlushedChangesToNewSessionCloseOldSession(s);
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();

    assertInsertCount(2);
    assertUpdateCount(instrumented ? 0 : 4);
    clearCounts();

    TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
    s = openSession();
    s.createQuery("delete from NumberedNode where name like 'grand%'").executeUpdate();
    s.createQuery("delete from NumberedNode where name like 'child%'").executeUpdate();
    s.createQuery("delete from NumberedNode").executeUpdate();
    TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
  }