JmixRepository load entities with stale data

Hello,

I’m experiencing a data consistency issue where changes saved via DataManager are not visible when immediately querying with JmixDataRepository in the same transaction.

Issue

I have two services that run sequentially within the same @Transactional method:

Service 1 - SalesOrderService (saves entity with DataManager):

  @Component
  public class SalesOrderService {
      private final DataManager dataManager;
      private final BillingService billingService;

      @Transactional
      public void computeTimerItems(SalesOrder salesOrder) {
          // ... load items and process ...

          for (SalesOrderItem currentItem : activeItems) {
              // simplified logic
              currentItem.updateTimer();

              // Save with DataManager - qty is now 74
              dataManager.save(currentItem);
              System.out.println("After DataManager.save() - qty: " + currentItem.getQty()); // Outputs: 74
          }

          // Immediately call billing service
          billingService.computeTimerItems(salesOrder);
      }
  }

Service 2 - BillingService (queries with JmixDataRepository):

  @Component
  public class BillingService {
      private final SalesOrderItemRepository salesOrderItemRepository;
      private final DataManager dataManager;

      @Transactional
      public void computeTimerItems(SalesOrder salesOrder) {
          // Query via repository - gets OLD value (33) instead of 74
          List<SalesOrderItem> activeBillings = salesOrderItemRepository
                  .findTimerBillingBySalesOrder(salesOrder.getId());

          System.out.println("After repository query - qty: " + activeBillings.get(0).getQty()); // Outputs: 33 (stale data!)

          // ... rest of billing logic uses incorrect qty value ...
      }
  }

Repository definition:

  @Repository
  public interface SalesOrderItemRepository extends JmixDataRepository<SalesOrderItem, UUID> {

      @Query("select e from repos_SalesOrderItem e where e.saleOrder.id = :salesOrderId " +
             "and e.timerStarts is not null and e.previousSalesOrder is null")
      List<SalesOrderItem> findTimerBillingBySalesOrder(@Param("salesOrderId") UUID salesOrderId);
  }

What’s Happening

  1. DataManager.save() updates qty to 74 and marks it dirty in the persistence context
  2. JmixDataRepository query executes immediately and retrieves 33 from the database
  3. The changes haven’t been flushed yet, so the repository sees stale data
  4. NOTE that the stale data happened on occasions (sometimes it works, sometimes it doesn’t)

Questions

  1. Is this expected behavior? Does DataManager.save() not automatically flush changes within a transaction?
  2. What’s the recommended approach? Should I:
    • Use EntityManager.flush() after DataManager.save()?
    • Replace the repository query with DataManager.load() for consistency?
    • Use SaveContext with specific flush settings?
  3. Best practices: When mixing DataManager and JmixDataRepository in the same transaction, what should I be aware of regarding persistence context visibility?

Environment

  • Jmix version: 2.5.2

Any guidance on the correct pattern would be greatly appreciated!

Hi Hiro,

DataManager always flushes changes to the database, even when the transaction is not closed. So each invocation of DataManager works with its own persistence context.

Your code seems correct and should not cause any issues. Check that you don’t have any event listeners that may affect the process.

If the problem persists, please provide a test project (on the latest Jmix version) where the problem is reproduced.

Regards,
Konstantin