Search code examples
javaspringtransactionsspring-transactionsjava-ee-7

Persisting detached object got error "during synchronization a new object was found through a relationship that was not marked cascade PERSIST"


I'm getting error during synchronization a new object was found through a relationship that was not marked cascade PERSIST: Wallet ...
I know the error is normally due to you don't have CascadeType.PERSIST and don't persist that entity specifically, but my story might be different as I did persist the entity.

I'm creating User in a transaction, then pass the User to a new transaction, in which wallet is created and attached to User.
The error occurs when exiting createUser function.
While I'm aware it's a bad idea passing a managed object to new transaction and make changes there, I expect the code to work if in Spring context. But I'm not sure why it throws error in J2EE.

I've also found out you can fix it by doing one of following before exiting createUser

  1. Merge the wallet again so that the object is managed again, OR
  2. get the newly created wallet from DB again and attach it to user. So that when exiting createUser, it knows wallet is not a new entity but already persisted.

Appreciate it if someone can tell me what's different between J2EE and Spring that this code doesn't work in the former one.

// existing transaction 
public void createUser(){
        User user = userRepo.createUser();
        walletService.createAndAttachWalletToUser(user);
        // add to fix
        // user.setWallet(walletService.merge(user.getWallet())); OR
        // user.setWallet(walletService.getWallet(user.getWallet().getId()));
}

// WalletService class
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void createAndAttachWalletToUser(User user){
        Wallet wallet = walletRepo.createWallet();
        user.setWallet(wallet);
}

Solution

  • The question has been left unanswered for a while so posting the walkaround here:

    You can fix it by doing one of following before exiting createUser

    Merge the wallet again so that the object is managed again, OR get the newly created wallet from DB again and attach it to user. So that when exiting createUser, it knows wallet is not a new entity but already persisted.