Reference to concrete revision of entity

142 Views Asked by At

I have an entity with a reference to another entity, something like this:

@Entity(name = "MyCustomEntity")
@Table(name = "my_custom_entity")
public class MyCustomEntity {

    @Id
    Integer id;

    @ManyToOne
    @JoinColumn(name = "profile_id")
    OtherEntity other;
}

As it turns out, business logic dictates that OtherEntity should not be mutable in this context. Since you can still change the entity outside this context, I thought it was easiest to change the reference from MyCustomEntity to an Envers revision.

I could replace the reference with this snippet:

@Entity(name = "MyCustomEntity")
@Table(name = "my_custom_entity")
public class MyCustomEntity {

    @Id
    Integer id;

    Integer otherId;
    Integer revision;
}

OtherEntity getOther(MyCustomEntity entity) throws Exception {
   return auditReader.find(OtherEntity.class, entity.otherId, entity.revision);
}

But I'd lose a couple of Hibernate features that I'd rather have.

Is there a better way to reference an Envers revision?

1

There are 1 best solutions below

3
On

Based on the fact you simply want to enforce immutability with the relationship between the two entities, why not simply make use of the @Immutable annotation here rather than trying to manipulate this through your model.

@Entity(name = "MyCustomEntity")
@Table(name = "my_custom_entity")
public class MyCustomEntity {
  @Id
  private Integer id;

  @ManyToOne
  @JoinColumn(name = "profile_id")
  @Immutable
  private OtherEntity other;

  ...
}

But it's important to understand that Immutable in this content applies solely to ORM.

Lets say you perform the following actions

  1. Create MyCustomEntityrevision pointing to OtherEntity.
  2. Modify OtherEntity (now has a higher revision number than MyCustomEntity)
  3. Modify MyCustomEntity (now has a higher revision number than OtherEntity)
  4. Query MyCustomEntity with latest revision.

That latest revision will point to the OtherEntity with modifications made in step 2. The immutability annotation simply doesn't allow changing the FK reference.

Does that solve your issue?

UPDATE

I want the MyCustomEntity to always point to the same version of OtherEntity. So even when OtherEntity changes, MyCustomEntity should not be able to see the changes.

That is precisely how Envers works.

The MyCustomEntity will only return the related association with a revision number that is equal-to or less-than its queried revision.

That means if you modify OtherEntity and then query MyCustomEntity, the returned instance of OtherEntity would not contain those recent changes.

The only time that MyCustomEntity would return the latest snapshot of the OtherEntity association would be if MyCustomEntity is modified in the same transaction or a future transaction after OtherEntity.

Associations are always returned with the associated entity-type having a revision number than is <= the queried entity's revision number.

I'm changing both.

If you're changing both, then the order in which you perform those changes will play into what snapshot the relationship will return in audit queries.

If you're goal is to somehow pin a revision, there really isn't a good logical way to do that, at least not within the same transaction boundary anyway given how Envers performs its logic in a pre-commit transaction callback.