Hi Mortoza,
Thank you for the test project and the explanation.
The problem stems from the fact that your queries defined in entity listeners run on the database which does not yet contain changes that have been made to entities in memory. This is explained here in the docs. In theory, you could set FlushModeType.AUTO
to the queries, and then ORM would flush memory changes to the database prior to the query execution. But it would hit performance because of additional database operations, and also fire BeforeInsert entity listeners for the entities being saved first time, which may introduce some complexity.
Better fully use the persistence context: you already have all changes in memory, so just traverse your data model and do calculations. For example, DeliveryOrderLineEntityListener
updating related OrderLine
is shown below:
@Component("sales_DeliveryOrderLineEntityListener")
public class DeliveryOrderLineEntityListener implements BeforeDeleteEntityListener<DeliveryOrderLine>, BeforeInsertEntityListener<DeliveryOrderLine>, BeforeUpdateEntityListener<DeliveryOrderLine> {
@Inject
private PersistenceTools persistenceTools;
@Override
public void onBeforeDelete(DeliveryOrderLine entity, EntityManager entityManager) {
// related entities can be detached, so if you want to update them, merge first
OrderLine line = entityManager.merge(entity.getOrderLine());
line.setDoQuantity(line.getDoQuantity().subtract(entity.getQuantity()));
}
@Override
public void onBeforeInsert(DeliveryOrderLine entity, EntityManager entityManager) {
OrderLine line = entityManager.merge(entity.getOrderLine());
line.setDoQuantity(line.getDoQuantity().add(entity.getQuantity()));
}
@Override
public void onBeforeUpdate(DeliveryOrderLine entity, EntityManager entityManager) {
OrderLine line = entityManager.merge(entity.getOrderLine());
BigDecimal oldDoQty = (BigDecimal) persistenceTools.getOldValue(entity, "quantity");
if (oldDoQty == null)
oldDoQty = BigDecimal.ZERO;
line.setDoQuantity(line.getDoQuantity().subtract(oldDoQty).add(entity.getQuantity()));
}
}
OrderLineEntityListener
updating the order state depending on doQuantity
:
@Component("sales_OrderLineEntityListener")
public class OrderLineEntityListener implements BeforeDeleteEntityListener<OrderLine>, BeforeInsertEntityListener<OrderLine>, BeforeUpdateEntityListener<OrderLine> {
@Override
public void onBeforeDelete(OrderLine entity, EntityManager entityManager) {
updateSalesOrderHeaderStatus(entity, entityManager);
}
@Override
public void onBeforeInsert(OrderLine entity, EntityManager entityManager) {
updateSalesOrderHeaderStatus(entity, entityManager);
}
@Override
public void onBeforeUpdate(OrderLine entity, EntityManager entityManager) {
updateSalesOrderHeaderStatus(entity, entityManager);
}
private void updateSalesOrderHeaderStatus(OrderLine orderLine, EntityManager em){
Order order = em.merge(orderLine.getOrder());
BigDecimal doQty = order.getLines().stream()
.map(OrderLine::getDoQuantity)
.reduce(BigDecimal.ZERO, BigDecimal::add);
if (doQty.equals(BigDecimal.ZERO)) {
order.setOrderStatus(OrderStatus.OPEN);
return;
}
BigDecimal qty = order.getLines().stream()
.map(OrderLine::getQuantity)
.reduce(BigDecimal.ZERO, BigDecimal::add);
if (qty.compareTo(doQty) > 0) {
order.setOrderStatus(OrderStatus.PARTIALLY_USED);
} else {
order.setOrderStatus(OrderStatus.CLOSED);
}
}
}
See the whole project attached.
sample-sales.zip (125.7 KB)