Noixes
Noixes

Reputation: 1178

Synchronize changed entities in the same transaction

I have a problem with a transactional method that changes an entity and wants to update it in some other way.

At first i get the entity A from the database with the entitymanager method "get". Then i get a related entity B where A to B is type of one to one (optional). (So the id field of B is inside the table of A). Now i want to remove the entity B via a service method. Therefore i have to use the ID of B.

Inside the service method i get B from the entity manager (now B'). Then i get A' from the aquired B'. Then i remove the link A' to B' when it is present via A'.setB(null) followed by a serviceOfA.save(A').

Then i delete B' via serviceOfB.delete(B').

When the method for removal of B via the id is completed i want to change properties of the instance A. Create another instance of B for example. Now when i get A via the entitymanager again hibernate throws a org.hibernate.exception.ConstraintViolationException for an object that should be added to the new B'' instance that is added to A.

I think the issue has something to do with the removal method that changed the instance A' and therefore A can not be reloaded. But how can i reload the new state of A? Please have a look below:

@Transactional
    public void compeleteSomething(
            @NonNull String location,
            @NonNull String nameOfA) throws SomeException{
        A a= serviceOfA.get(nameOfA);

        B b= a.getB();
        someService.removeBAndLinkToA(b.getId()); // <-- maybe here is the error

        B newInstanceOfB = someService.createBOn(location);
        someService.setBonA(serviceOfA.get(nameOfA), newInstanceOfB); // <-- serviceOfA.get() throws error

        [...]
    }

And here the method of someService.removeBAndLinkToA(#)

@Transactional
    public void removeBAndLinkToA(
            @NonNull Long id) {
        B b = serviceOfB.get(id);

        A a = b.getA();
        if (a!= null) {
            a.setB(null);
            serviceOfA.save(a); // <-- This should cause the error?
        }

        serviceOfB.delete(b);
    }

How can i avoid this issue? Many thanks!

Upvotes: 0

Views: 2202

Answers (1)

Paulo Ara&#250;jo
Paulo Ara&#250;jo

Reputation: 569

When working inside a transaction, entitymanager is expected to deal with all relashionships until commit, provided it is injected with proper scope. You do not need to save the entity at each step nor retrieve it again from database: its state is managed by the entitymanager (no pun intended).

In short, your completeSomething method does not need to call another service method. Just make b.setA(null), a.setB(new B()) and return. Everything should work as expected:

@Transactional
public void completeSomething(String aId) {
    A a = entityManager.find(A.class, aId);
    B b = a.getB();
    a.setB(new B());
    b.setA(null);
} // container should end transaction here, commiting changes to entities

If the transaction is successful, the container will commit changes to entities and the changes will be reflected on database as long the @PersistenceContext has PersistenceContextType.TRANSACTION type, which is the default.

Upvotes: 1

Related Questions