Search code examples
javahibernatejpahibernate-envers

I am trying to connect 2 tables to have same rev number using hibernate envers?


I have customer entity that have List of accounts and each entity have audited tables,so tables generated will be : (CUSTOMERS ,ACCOUNTS ,CUSTOMERS_AUD ,ACCOUNTS_AUD)

how can I connect the change of accounts with the change of customer in one rev number? hibernate envers gives separated version (rev number) for each table ?

The generated tables of my code:

CUSTOMERS_AUD TABLE

   | ID  | REV   | REVTYPE |name  |account_num|ACCOUNTID|
   |:----|------:|:-------:|:----:|:---------:|:-------:|
   | 1   |  1    |     0   |Ann   |1234567897 |1        |
   | 1   |  3    |     1   |Alex  |1234567897 |1        |
   | 1   |  5    |     1   |Alex  |7777777777 |1        |

ACCOUNTS_AUD TABLE

   | ID         | REV   | REVTYPE |name  |account_num|
   |:-----------|------:|:-------:|:----:|:---------:|
   | 1          |  2    |     0   |Ann   |1234567897 |
   | 1          |  4    |     1   |Alex  |7777777777 |

SAMPLE ENTITIES

    @Entity

    @Table(name="CUSTOMERS")
    @Audited
    public class Customer  implements Serializable {
    
    .
    .
    
    @ManyToOne
    @org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.REPLICATE)
    @JoinColumn(name="ACCOUNTNUMBERCOMBOBOXID", nullable=true)
    private Account accountNumberComboBox;
    
    public static final String REF_CUSTOMERS_ACCOUNTS = "refCustomersAccounts";
    @OneToMany(mappedBy = "refCustomers")
    @org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.REPLICATE)
    private List<Account> refCustomersAccounts;
    .
    .
    .
    
    }
    
    @Entity
    
    @Table(name="ACCOUNTS")
    @Audited
    public class Account  implements Serializable {
    
    .
    .
    
    public static final String REF_CUSTOMERS = "refCustomers";
    @ManyToOne
    @org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.REPLICATE)
    @JoinColumn(name="REFCUSTOMERSID", nullable=true)
    private Customer refCustomers;
    .
    .
    .
    
    }

THE RESULTS THAT I WANT

CUSTOMERS_AUD TABLE

   | ID  | REV   | REVTYPE |name  |account_num|ACCOUNTID|
   |:----|------:|:-------:|:----:|:---------:|:-------:|
   | 1   |  1    |     0   |Ann   |1234567897 |1        |
   | 1   |  2    |     1   |Alex  |1234567897 |1        |
   | 1   |  3    |     1   |Alex  |7777777777 |1        |

ACCOUNTS_AUD TABLE

   | ID         | REV   | REVTYPE |name  |account_num|
   |:-----------|------:|:-------:|:----:|:---------:|
   | 1          |  1    |     0   |Ann   |1234567897 |
   | 1          |  2    |     0   |Ann   |1234567897 |
   | 1          |  3    |     1   |Alex  |7777777777 |

Spring boot application

@SpringBootApplication
public class JpaDemoApplication implements CommandLineRunner {

    @Autowired
    private ApplicationContext context;

    public static void main(String[] args) {
        SpringApplication.run(JpaDemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        CustomerRepo customerRepo = context.getBean(CustomerRepo.class);
        AccountRepo accountRepo = context.getBean(AccountRepo.class);
        AccountTypeRepo accountTypeRepo = context.getBean(AccountTypeRepo.class);

        Accounts account = new Accounts();
        Customers customer = new Customers();

        customer.setId(1L);

        account.setId(1L);
        account.setFromDate(new Date());
        account.setToDate(new Date());
        account.setNewAcountNumber("1234567897");
        account.setOwner("Ann");


        customer.setAccountNumber(account.getNewAcountNumber());
        customer.setCode("CODE");
        customer.setName(account.getOwner());
        customer.setFromDate(new Date());
        customer.setToDate(new Date());
        customer.setAccountNumberComboBox(account);

        accountRepo.save(account);

        customerRepo.save(customer);//0

        customer.setName("Alex");
        customerRepo.save(customer);//1

        account.setNewAcountNumber("7777777777");
        accountRepo.save(account);

    }
}

Account Repo

@Repository
public interface AccountRepo extends CrudRepository<Accounts,Long> {
}

Customer Repo

@Repository
public interface CustomerRepo extends CrudRepository<Customers, Long> {
}

Solution

  • The revision number is associated with the transaction, so whatever operations you perform in a single transaction will be audited and stored with the same revision number, always.

    Since you did not show your persistence code I can only guess at this point that the code is likely saving the Customer entity in one transaction and in a subsequent transaction you're saving the Account entity.

    If you save them both within the same transaction, they'll get the same revision number assigned to their audit rows.