2014-09-27 72 views
0

我使用spring + JPA作爲orm框架。我的項目層結構就像web - > Service - > Domain DAO - > genericDAO。 在genericDAO中,我使用@PersistenceContext注入EntityManager。javax.persistence.EntityNotFoundException:已刪除的實體傳遞給persist

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

這裏之前被刷新爲hibernate documentation

事務中的持久實例報價(即對象加載,保存, 創建或會話查詢)可以被 應用程序操縱,並且當會話刷新時,對持久狀態的任何更改將被持久 。沒有必要調用一個特定的方法(如update(),它具有不同的目的),以使您的修改持久。直接更新對象狀態的最直接方法是加載()它 ,然後在Session打開時直接對其進行操作。

有時這種編程模型效率低下,因爲它需要在同一個會話中同時加載SQL SELECT到 對象和SQL UPDATE來保持其更新狀態。 Hibernate通過使用分離的實例提供了一種替代方法。

但我會盡量簡單解釋一下。你的方法getOrderFromSession()是事務性的,並且hibernate對象在它內部打開了會話,但是當對象order返回給你時,它已經從會話中分離出來,並且hibernate不知道你在用它做什麼,直到你再次堅持他。因此,對於已刪除的項目,當保存該對象時,hibernate會發現它,直到此時hibernate中的對象具有與getOrderFromSession()返回時的狀態相同的狀態。

這裏有detailed explanation

UPDATE:

當你在Hibernate中刪除對象,在java對象變得短暫。它仍然存在於Java中,刪除後可以使用它。

Session.delete()將從數據庫中刪除對象的狀態。但是,您的 應用程序仍然可以保存對已刪除對象的引用。 最好把delete()當作持久化實例, transient。

+0

由於實體管理器是共享的,刪除訂單項和加載產品發生在同一個entityManager中。那爲什麼是錯誤? – javafan 2014-09-27 18:36:35

相關問題