2014-09-27 2 views
0

Я использую Spring + JPA в качестве рамки orm. Моя структура слоя проекта похожа на веб -> Сервис -> Домен DAO -> genericDAO. В genericDAO я инъецирую EntityManager, используя @PersistenceContext.javax.persistence.EntityNotFoundException: удаленный объект передан для сохранения

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: удаленный объект, переданный для сохранения: [core.entity.OrderItem #].

Я не понимаю, если элемент заказа уже отмечен как удаленный в диспетчере объектов, почему он пытается сохранить.

Когда я раскомментирую строку Y, которая внутренне скрывает диспетчер объектов, он работает нормально. Я не понимаю, почему он требует менеджера сущностей должны быть промыт перед выполнением строки X

ответ

1

Вот цитата из hibernate documentation

транзакционных упорных случаев (т.е. объекты загружены, сохранены, созданы или запрошены сессиями) может быть обработано приложением , и любые изменения в постоянном состоянии будут сохраняться , когда Сессия будет очищена. Нет необходимости вызывать конкретный метод (например, update(), который имеет другую цель), чтобы ваши изменения были постоянными. Самый простой способ обновить состояние объекта - загрузить() , а затем манипулировать им напрямую, когда сеанс открыт.

Иногда эта модель программирования неэффективна, так как требуется в том же сеансе, что и SQL SELECT для загружает объект и SQL UPDATE, чтобы сохранить его обновленное состояние. Hibernate предлагает альтернативный подход, используя отдельные экземпляры.

Но я попробую объяснить проще. Ваш метод getOrderFromSession() - это транзакционные и спящие объекты, внутри которых открыт сеанс, но когда объект возвращается order, он был отделен от сеанса, а спящий режим не знает, что вы делаете с ним, пока вы не повторите его. Поэтому для удаленных элементов hibernate обнаружит, когда вы сохраните этот объект, пока объект в спящем режиме не будет иметь такое же состояние, какое было в момент, когда getOrderFromSession() вернул его.

Здесь у вас есть detailed explanation

UPDATE:

При удалении объекта в спящем режиме, объект в Java становится временным. Он все еще существует в java, и после удаления вы можете его использовать.

Session.delete() удалит состояние объекта из базы данных. Однако ваше приложение все еще может хранить ссылку на удаленный объект. Лучше всего думать о delete() как о создании постоянного экземпляра, переходного процесса.

+0

Поскольку диспетчер объектов является общим, удаление элемента заказа и загрузка продукта происходит в том же entityManager. Тогда почему ошибка? – javafan

Смежные вопросы