Sameera Manorathna
Sameera Manorathna

Reputation: 618

How to handle multiple entity update in the same transaction in Spring Data REST

Is anyone having an idea on how to handle multiple entity updates within the same transaction in Spring Data REST ? The same thing can be handle within Spring controller methods using the @Transactional annotation. If I am correct, Spring Data REST executes every execution event within separate transactions. So multiple entity updates cannot be handled in a proper way.

I am having issues updating 2 entities (ABC and PQR) within the same transaction and rolling back the ABC entity when the PQR entity is failed.

// ABC repository
    @RepositoryRestResource
    public interface ABCEntityRepository extends MongoRepository<ABC, String> {
    }

// PQR repository
    @RepositoryRestResource
    public interface PQREntityRepository extends MongoRepository<PQR, String> {
    }

// ABC repository handler
    @RepositoryEventHandler
    public class ABCEventHandler {

        @Autowired
        private PQREntityRepository pqrEntityRepository;


        @HandleBeforeSave
        public void handleABCBeforeSave(ABC abc) {
          log.debug("before saving ABC...");
        }

        @HandleAfterSave
        public void handleABCAfterSave(ABC abc) {
          List<PQR> pqrList = pqrEntityRepository.findById(abc.getPqrId());

          if (pqrList != null && !pqrList.isEmpty()) {
            pqrList.forEach(pqr -> {
              // update PQR objects
            }
          }

          // expect to fail this transaction
          pqrEntityRepository.saveAll(pqrList);
        }
    }

since @HandleAfterSave method is executed in a separate transaction, calling HandleAfterSave method means the ABC entity updation is already completed and cannot rollback, therefore. Any suggestion to handle this ?

Upvotes: 3

Views: 3268

Answers (2)

orirab
orirab

Reputation: 3353

I'm not sure I understood your question correctly, but I'll give it a try.

I'd suggest to have a service with both Repositories autowired in, and a method annotated with @Transactional that updates everything you want.

This way, if the transaction fails anywhere inside the method, it will all rollback.

If this does not answer your question, please clarify and I'll try to help.

Upvotes: 0

Oliver Drotbohm
Oliver Drotbohm

Reputation: 83131

Spring Data REST does not think in entities, it thinks in aggregates. Aggregate is a term coming from Domain-Driven Design that describes a group of entities for which certain business rules apply. Take an order along side its line items for example and a business rule that defines a minimum order value that needs to be reached.

The responsibility to govern constraints aligns with another aspect that involves aggregates in DDD which is that strong consistency should/can only be assumed for changes on an aggregate itself. Changes to multiple (different) aggregates should be expected to be eventually consistent. If you transfer that into technology, it's advisable to apply the means of strong consistency – read: transactions – to single aggregates only.

So there is no short answer to your question. The repository structure you show here virtually turns both ABCEntity and PQREntity into aggregates (as repositories only exist for aggregate roots). That means, OOTB Spring Data REST does not support updating them in a single transactional HTTP call.

That said, Spring Data REST allows the declaration of custom resources that can take responsibility of doing that. Similarly to what is shown here, you can simply add resources on additional routes to completely implement what you imagine yourself.

Spring Data REST is not designed to produce a full HTTP API out of the box. It's designed to implement certain REST API patterns that are commonly found in HTTP APIs and will very likely be part of your API. It's build to avoid you having to spend time on thinking about the straight-forward cases and only have to plug custom code for scenarios like the one you described, assuming what you plan to do here is a good idea in the first place. Very often requests like these result in the conclusion that the aggregate design needs a bit of rework.

PS: I saw you tagged that question with spring-data-mongodb. By default, Spring Data REST does not support MongoDB transactions because it doesn't need them. MongoDB document boundaries usually align with aggregate boundaries and updates to a single document are atomic within MongoDB anyway.

Upvotes: 1

Related Questions