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;
}
You might want to use Hibernate Envers to create a versioning table instead of creating separate log objects.