Update object and get old value via JPA

2.5k Views Asked by At

I want to log changes of an account. Therefore, I have created an entity class that shall log the changes. Each time, an account entity is saved or updated a logging object is created.

When the object is updated with a new balance the old balance shall be retrieved from the database. As the object is bound to the session retrieving its old balance is not trivial, because one always gets the new balance.

To circumvent, I detached the object from the session. Yet, this seems to be a workaround that should be avoided.

The following code snippets shall illustrate the scenario.

Any suggestion is highly appreciated!

The test:

public class AccountServiceTest
{
    @Autowired
    AccountService        accountService;

    @Autowired
    ChangeAccountService  changeAccountService;

    @Test
    public void shouldHaveChangeLog()
    {
        Account account = this.accountService.updateAccount(new Account(0, 10.0));
        assertThat(account.getId(), is(not(0L)));

        account.setBalance(20.0);
        account = this.accountService.updateAccount(account);

        final List<ChangeAccountLog> changeResultLogs = this.changeAccountService.findAll();
        assertThat(changeResultLogs.get(1).getNewBalance(), is(not(changeResultLogs.get(1).getOldBalance())));
    }
}

The service of the domain class to be logged:

@Service
public class AccountService
{
    @Autowired
    AccountRepository accountRepository;

    @Autowired
    ChangeAccountService  changeAccountService;

    public Account findById(final long id)
    {
        return this.accountRepository.findOne(id);
    }

    public Account updateAccount(final Account account)
    {
        this.changeAccountService.saveLog(account);

        return this.accountRepository.save(account);
    }
}

The service of the logging class:

@Service
public class ChangeAccountService
{
    @Autowired
    AccountService                accountService;

    @Autowired
    ChangeAccountLogRepository    repository;

    public ChangeAccountLog save(final ChangeAccountLog changeAccountLog)
    {
        return this.repository.save(changeAccountLog);
    }

    public List<ChangeAccountLog> findAll()
    {
        return this.repository.findAll();
    }

    public ChangeAccountLog saveLog(final Account account)
    {
        final Double oldAccountBalance = oldAccountBalance(account);
        final Double newAccountBalance = account.getBalance();
        final ChangeAccountLog changeAccountLog = new ChangeAccountLog(0, oldAccountBalance, newAccountBalance);

        return this.repository.save(changeAccountLog);
    }

    @PersistenceContext
    EntityManager   em;

    private Double oldAccountBalance(final Account account)
    {
        this.em.detach(account);

        final Account existingAccount = this.accountService.findById(account.getId());

        if (existingAccount != null)
        {
            return existingAccount.getBalance();
        }
        return null;

    }
}

The class of which objects are to be logged:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Account
{
     @Id
     @GeneratedBalance
     protected    long    id;

     Double balance;
}

The logging class:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class ChangeAccountLog
{
     @Id
     @GeneratedBalance
     private long     id;

     private Double    oldBalance;
     private Double    newBalance;
}
1

There are 1 best solutions below

1
On

You might want to use Hibernate Envers to create a versioning table instead of creating separate log objects.