I am implementing an online shop. I have the following code for saving an order:
@Service
@Transactional
public class OrderServiceImpl extends GenericServiceImpl<Order, Integer> implements OrderService {
@Inject
private ItemRepository itemRepository;
@Override
public void saveOrder(Order order) {
this.updateItemsAccordingToOrderedQuantities(order);
repository.save(order);
}
private void updateItemsAccordingToOrderedQuantities(Order order) {
List<OrderedItem> orderedItems = order.getOrderedItems();
for (OrderedItem orderedItem : orderedItems) {
// fetch from database
Item item = itemRepository.findOne(orderedItem.getItem().getId());
item.reduceWeightInColdStoreBy(orderedItem.getWeight());
itemRepository.update(item);
}
}
}
Before actually saving the order I update the "weight" property of each item (some quantity gets sold with this order, so there is less left).
OrderedItem
objects hold the reference to Item
, but I want to fetch the fresh Item
from the database (to additionally check there is enough on sale, in case Item
table in database changed and UI didn't update before user submitted order). findOne
method I am calling for this purpose is implemented as follows:
@Repository
public class GenericRepositoryImpl<T, ID extends Serializable> implements GenericRepository<T, ID> {
@PersistenceContext
EntityManager em;
protected Class<T> entityClass;
public GenericRepositoryImpl(Class<T> entityClass) {
this.entityClass = entityClass;
}
@Override
public T findOne(ID id) {
return em.find(entityClass, id);
}
}
After the call item
is not null
, but it is not fetched from the database: I have EclipseLink logging turned on, at "FINEST" level, and there is no SELECT
query.
I thought that it is because EclipseLink has this item
in its persistence context, so it doesn't execute the query. So I've tried adding em.clear()
before return
in findOne
method implementation, but it didn't help.
How do I actually get the fresh item
from the database?
Thank you in advance.
P.S. I've tried querying explicitly in my findOne
method, like so:
@Override
public T findOne(ID id) {
T result = null;
try {
TypedQuery<T> query = em.createQuery("SELECT e FROM " + entityClass.getName() + " e", entityClass);
result = query.getSingleResult();
} catch (RuntimeException e) {
e.printStackTrace();
}
return result;
}
This way I get the exception: java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: ftcApp.model.Order@cf616dce
. I have no idea why, because I'm not doing persist
.