Set, Refresh, Commit

Yes, you’re right.

Remember that you pass detached entities to the service. It means that you need to attach them to Persistence Context using entity manager. To save network traffic, you can even send transaction IDs to the service instead of whole transactions and fetch them in the service. Do not forget to mark the method with @Transactional annotation, or open a transaction manually as described in the documentation.

Another option - you can use DataManager in your service, it can work with detached entities. You can save all transactions using dataManager.commit() and pass all transactions to this method.

I made these modifications and it works!
However I’m not sure that is the right approach, I have to merge any if entity t (and I have a dozen of if(s)…is there any way to gather and commit all setStatus modifications once (//em.merge(transactions)) like dataContext.commit();? I saw that dataContext is not available in the middleware.

Service(StatusService.NAME)
public class StatusServiceBean implements StatusService {
    @Transactional
    public void updateTransactions(Set<Transaction> transactions){
 EntityManager em = persistence.getEntityManager();
      transactions.forEach(a -> {
       if (t.getStatus() == TrStatusEnum.PROCESSING) {
                t.setStatus(TrStatusEnum.INVOICED);
                em.merge(a);
            }
         if(logic2){
                t.setStatus(TrStatusEnum.INVOICED);
                em.merge(a);
          }
......................
        });

I don’t know how to do it…

You can commit all entities at once using data manager, as I mentioned before. Does it work for you?

I saw but I don’t know exactly where should I use it.

Service(StatusService.NAME)
public class StatusServiceBean implements StatusService {
    @Transactional
    public void updateTransactions(Set<Transaction> transactions){
 EntityManager em = persistence.getEntityManager();
      transactions.forEach(a -> {
       if (t.getStatus() == TrStatusEnum.PROCESSING) {
                t.setStatus(TrStatusEnum.INVOICED);
                em.merge(a);
            }
         if(logic2){
                t.setStatus(TrStatusEnum.INVOICED);
                em.merge(a);
          }
......................
        });
      dataManager.commit();

    }

doesn’t work.

Well, just have a look at the DataManager’s API:

    /**
     * Commits new or detached entity instances to the data store.
     * @param entities  entities to commit
     * @return          set of committed instances
     */
    EntitySet commit(Entity... entities);

Moreover, Datamanager works with detached entities, as I mentioned before, there is no need to merge them to the persistence context.

Sorry, I forgot to comment merge() when I posted the snippet code.
Finally done!

CommitContext commitContext = new CommitContext(transactions); 
dataManager.commit(commitContext);

But I don’t understand why is necessary a new CommitContext Object instead of dataManager.commit(transactions);`
This CommitContext class is specific Cuba…such kind of persistence context…

CommitContext is just a container for entities used by DataManager. It should work fine without it, because if you look into the source code and try to debug, you’ll see that array of entities is wrapped into commit context anyway inside the data manager implementation.

For me the following code with Stream API works. It commits entities one by one though. But it’s not about CUBA, it’s about “just coding”, I can refactor it to bulk commit if needed.

    @Subscribe("transactionsTable.process")
    public void onTransactionsTableProcess(Action.ActionPerformedEvent event) {
        Set<Transaction> transactions = transactionsTable.getSelected();
        transactionsService.updateTransactions(transactions).forEach(t ->
        {
            Transaction tr = dataContext.merge(t);//merging an updated entity into screen data context to be able to update it programmatically
            transactionsDc.replaceItem(tr);//replacing the item in the container to display it on the screen
        });
    }

```java
    public List<Transaction> updateTransactions(Collection<Transaction> transactions) {
        return transactions.stream()
                .filter(t -> t.getStatus() == TrStatusEnum.PROCESSING)
                .map(t -> {
                    t.setStatus(TrStatusEnum.INVOICED);
                    return dataManager.commit(t);
                }).collect(Collectors.toList());
    }
1 Like

Yes you are right. It’s possible to refactor in this way.
Thank you very much Andrey. I truly appreciate your professionalism!

Best Regards,
-n

You’re welcome. Enjoy CUBA! :slight_smile: