javax.persistence.EntityNotFoundException:已删除的实体传递给persist

时间:2014-09-27 16:38:36

标签: spring hibernate jpa entitymanager transactional

我使用spring + JPA作为orm框架。我的项目层结构就像web - >服务 - >域DAO - > genericDAO。 在genericDAO中,我使用@PersistenceContext注入EntityManager。

genericDAO.delete(Object o) {
    o = entityManager.merge(o);
    entityManager.remove(o);
}

genericDAO.saveOrUpdate(Object o) {
    entityManager.merge(o);
    entityManager.flush();
}

在服务层的一个方法中,我有以下操作。

// delete order item if already exists.
Order order = getOrderFromSession();
if (CollectionUtils.isNotEmpty(orderItems)) {
  Iterator<OrderItem> iterator = orderItems.iterator();
  while (iterator.hasNext()) {
     OrderItem orderItem = iterator.next();
     iterator.remove();
     orderDAO.deleteOrderItem(orderItem); // Which internall calls genericDAO.delete()
  }
}
//orderDAO.saveOrder(order) // line  Y
//Now create fresh order items submitted by jsp form.
for (ProductVO productVO : productList) {
 if (productVO.getQuantity() > 0) {
    orderItem = new OrderItem();
    Product product = productDAO.getProductByCode(productVO.getCode()); // line X
    orderItem.populateOrderItemByProduct(product, productVO.getQuantity(), order);
    order.addOrderItem(orderItem);
 }
}

第X行使用hql检索产品实体。但是当执行第X行时,我得到以下错误。 javax.persistence.EntityNotFoundException:传递给persist的已删除实体:[core.entity.OrderItem#]。

我不明白订单项是否已在实体管理器中标记为已删除,为什么它会尝试保留。

当我取消注释内部冲洗实体管理器的第Y行时,它工作正常。我不明白为什么在执行第X行之前需要刷新实体管理器

1 个答案:

答案 0 :(得分:1)

以下是hibernate documentation

的引用
  

事务持久化实例(即加载,保存的对象,   由Session创建或查询)可以被操作   应用程序,持久状态的任何更改都将保留   当会话被刷新时。无需调用特定方法(如update(),具有   一个不同的目的)使你的修改持久。最多   更新对象状态的直接方法是load()它   然后在Session打开时直接操作它。

     

有时这种编程模型是   效率低下,因为它需要在同一个会话中同时使用SQL SELECT   加载对象和SQL UPDATE以保持其更新状态。   Hibernate通过使用分离的实例提供了另一种方法。

但我会尝试解释更简单。你的方法getOrderFromSession()是事务性的,而hibernate对象在其中打开会话,但是当对象order返回给你时,它已经从会话中分离出来了,而hibernate不知道你在做什么,直到你再次坚持下去因此,对于已删除的项目,hibernate将在您保存该对象时找到,直到那时hibernate中的对象具有与getOrderFromSession()返回它时的状态相同的状态。

这里有detailed explanation

<强>更新

在hibernate中删除对象时,java中的对象变为瞬态。它仍然存在于java中,删除后你可以使用它。

  

Session.delete()将从数据库中删除对象的状态。您的   但是,应用程序仍然可以保存对已删除对象的引用。   最好将delete()视为制作持久化实例,   瞬变。