4

I've got the following setup:

@Entity
@Audited
public class House {

    @OneToOne(cascade = CascadeType.ALL)
    private Door frontDoor;
  
    // ...

}
@Entity
@Audited
public class Door {

    private String color;

    // ...

}

and then somewhere else in my code the following lines:

// #1: Creation of house
var house = new House();
var door = new Door();
door.setColor("red");
house.setFrontDoor(door);
houseRepository.save(door);

// #2: Modification of the front door
// (in another method)
var house = houseRepository.getById(/*...*/);
var door = house.getDoor();
door.setColor("blue");
houseRepository.save(house);

So what I get in my audit tables is something like this:

DOOR_AUD:

ID COLOR REV REVTYPE
1 red 1 0
1 blue 2 1

HOUSE_AUD:

ID FRONT_DOOR REV REVTYPE
2 1 1 0

However I need to get a new entry in HOUSE_AUD as well (like if I would modify a direct/primitive property in house):

ID FRONT_DOOR REV REVTYPE
2 1 1 0
2 1 2 1

Is there any way to tell Envers to create a new Revision for all affected parents?

1 Answer 1

2

So, after some research and tests, I'm here to present my results.

I encountered a similar question here on SO: How to Audit one-to-one relation through hibernate envers in bidirectional?

I realized my assumption about hibernate understanding this as a parent-child relation was wrong. According to this answer, @OneToOne even with cascading and doesn't make it a one-way directed relation. There are several workarounds for this, I thought for feature reference I might collect them here.

Solution I: Using an additional field

Add another field to House like a counter or a timestamp.

Pro: This is quite a straight-forward workaround and simple to understand.

Con: You'll need to make sure you update the field on every occasion when you update the frontDoor. Additionally, you need to extend your database table, and the entity gets polluted with a purely technical thing.

Solution II: Using Embeddable

It might be worth considering if @OneToOne is really the kind of relation you want to express. Maybe Door would be better suited as an @Embeddable.

Pro: You don't need to care for anything else.

Con: If Door would contain itself @Embedded fields, this might simply be no option. Also, you might use Door already in a different context where you need it to be a separate entity.

Solution III: Using Conditional Auditing

Didn't try or saw anyone doing this, but it might work ...

Solution IV: Change your approach to auditing

Maybe you can rethink your usage of the audit stuff and check (recursively?) for revisions in sub-entites when you need to get a list of all the different versions.


Hopefully, the Hibernate Team will address this in the future. However, it doesn't look too promising: HHH-13362

Not the answer you're looking for? Browse other questions tagged or ask your own question.