Quantcast
Channel: Recent Questions - Stack Overflow
Viewing all articles
Browse latest Browse all 12111

Get the new version before committing the transaction spring data jpa

$
0
0

I would like to know if it is possible to start a transaction to search for my entity, update the information, then call the JpaRepository save and upon return get the new version (I'm using @Version), as I would like to use the most current version to put in the my productUpdated event for example. If not, I will need to create a method just so that when I instantiate the event's record class, call product.getVersion() + 1, since there will always be a previous version, remembering that I need this because I save the event in a table also in the same transaction. Follow my current code

private Product update(final Product aProduct) {        final var aResult = this.productRepository.save(ProductJpaEntity.toEntity(aProduct));        return aResult.toDomain();}

this test:

transactionTemplate.execute(status -> {        try {            final var aProductFindById = this.productRepository.findById(aProduct.getId().getValue())                    .get().toDomain();            aProductFindById.updateStatus(ProductStatus.INACTIVE);            final var aProductUpdated = this.productGateway.update(aProductFindById);            // version in this moment is 0            System.out.println(aProductUpdated.getVersion());            this.outboxEventRepository.save(OutboxEventEntity.from(new TestListenerDomainEvent(                    String.valueOf(aProductUpdated.getVersion())            )));        return null;        } catch (Throwable t) {            status.setRollbackOnly();            this.productRepository.findById(aProduct.getId().getValue())                    .ifPresent(a -> System.out.println(a.getVersion()));            throw t;        }    });

After completing the transaction I can now get the new version value, if I can't get it directly from the save / update method return, I will need to create a method just to get the current version and add + 1. Of course, if there is no other solution.

I implemented an abstraction, here are the classes and here is how I'm using it at the moment, even though the event publisher throws an exception it doesn't rollback, I can get the newest version which would be the one that comes after the update, but it ends up not giving the rollback

public class TransactionResult<T> {    private final T successResult;    private final Error errorResult;    private TransactionResult(T aSuccessResult, Error aErrorResult) {        this.successResult = aSuccessResult;        this.errorResult = aErrorResult;    }    public static <T> TransactionResult<T> success(T aSuccessResult) {        return new TransactionResult<>(aSuccessResult, null);    }    public static <T> TransactionResult<T> failure(Error aErrorResult) {        return new TransactionResult<>(null, aErrorResult);    }    public boolean isSuccess() {        return this.successResult != null;    }    public boolean isFailure() {        return this.errorResult != null;    }    public T getSuccessResult() {        return this.successResult;    }    public Error getErrorResult() {        return this.errorResult;    } }

TransactionManager class:

public interface TransactionManager {<T> TransactionResult<T> execute(Supplier<T> action);}

TransactionManagerImpl:

@Componentpublic class TransactionManagerImpl implements TransactionManager {    private final PlatformTransactionManager manager;    public TransactionManagerImpl(PlatformTransactionManager manager) {        this.manager = manager;    }    @Override    public <T> TransactionResult<T> execute(Supplier<T> action) {        final var aTransactionTemplate = new TransactionTemplate(manager);        try {            T result = aTransactionTemplate.execute(status -> {                try {                    return action.get();                } catch (Exception e) {                    status.setRollbackOnly();                    throw e;                }            });            return TransactionResult.success(result);        } catch (Exception e) {            return TransactionResult.failure(new Error(e.getMessage()));        }    }}

event publisher impl:

@Componentpublic class EventPublisherImpl implements EventPublisher {    @Override    public <T extends DomainEvent> void publish(T event) {        throw new UnsupportedOperationException("Error: Not implemented yet");    }}

My usecase:

public Either<NotificationHandler, UpdateProductOutput> execute(UpdateProductCommand input) {        final var aNotification = NotificationHandler.create();        final var aProduct = this.productGateway.findById(input.id())                .orElseThrow(NotFoundException.with(Product.class, input.id()));        if (aProduct.getStatus().equals(ProductStatus.DELETED)) {            throw ProductIsDeletedException.with(aProduct.getId());        }        final var aCategoryId = input.categoryId() == null || input.categoryId().isBlank()                ? aProduct.getCategoryId()                : this.categoryGateway.findById(input.categoryId())                .orElseThrow(NotFoundException.with(Category.class, input.categoryId()))                .getId();        final var aName = input.name() == null || input.name().isBlank()                ? aProduct.getName()                : input.name();        final var aPrice = input.price() == null                ? aProduct.getPrice()                : input.price();        final var aProductUpdated = aProduct.update(                aName,                input.description(),                aPrice,                input.quantity(),                aCategoryId        );        aProductUpdated.validate(aNotification);        if (aNotification.hasError()) {            return Either.left(aNotification);        }        final var aResult = this.transactionManager.execute(() -> {            final var aProductSaved = this.productGateway.update(aProductUpdated);            System.out.println("after call update in usecase -> " + aProductSaved.getVersion());            this.eventPublisher.publish(ProductUpdatedEvent.from(aProductSaved));            return aProductSaved;        });        if (aResult.isFailure()) {            aNotification.append(new Error("error to update product"));            return Either.left(aNotification);        }        return Either.right(UpdateProductOutput.from(aProductUpdated));    }

it returns failure, but the transaction continues without rolling back.


Viewing all articles
Browse latest Browse all 12111

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>