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);
}
......................
});
/**
* 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());
}