15

I am thinking about switching from a self-implemented versioning-solution to Hibernate Envers, but I am not quite sure yet. I have read a lot about it, but I am concerned about schema changes and how Envers deals with them after having historized data according to an older schema.

What is your experience with Envers in this regard? How do you deal with schema changes and existing data with Envers?

Update 1:

It is not just about adding removing simple columns from a table, but e.g. when changing a simple Forein-Key-Relationship into a separate entity with two 1:n-relationships (M2M with attributed columns. This is a "logical" change in your data model. How do you deal with that when using Envers, when there is already historized data according to the old model? Is there an alternative to manually write sql-scripts and transfering them into the new representation?

Sakuraba
  • 2,631
  • 1
  • 19
  • 13

3 Answers3

4

In my experience, Envers simply copies every field from your entity table to its audit tables. The copied fields in the audit tables have no constraints on them, including nullability and foreign key constraints, so there's no problem with adding or removing such constraints on the real tables. Any kind of relationships you add to your entities will just be new audit columns and/or tables added under Envers, and it's up to you to correctly interpret them in their historical context.

For your example, if I understand correctly, of switching from a join-column-based relationship to a join-table-based one, you'd simply have the old join column coexisting with the join table, and at the point of the cutover, the former will cease being populated in favor of the latter. Your history will be completely preserved, including the fact that you made this switch. If you want all the old data to fit into the new model in the audit tables, it's up to you to do the migration.

Ryan Stewart
  • 126,015
  • 21
  • 180
  • 199
2

There shouldn't be problems with modifying the existing schema as Envers relies on your @Entities to create the audit tables. So if you add or remove a column from an existing table, as long as this change is reflected in your @Entity / @Audited JavaBean, it should be ok.

  • Thanks! Updated the question according to your reply. – Sakuraba Aug 01 '11 at 06:39
  • I don't yet see how this is not a problem? If for example I have one column, which will be deleted and replaced by two columns. The entity is updated, and I updated the history table to contain the 2 new columns, but what should happen with the removed column in the history table? Should it be removed, and history be manipulated? Should it remain and let the history table grow infinitely for each manipulation? It's not a matter of compilation error, because of course it will compile and work. – Thomas Stubbe Oct 06 '20 at 13:11
1

The foreign key refactoring should be fine with Envers. As Envers creates a join table even for one-to-many relationship, it should be straight to change it to become many-to-many relationship. I extracted one paragraph from official document:

9.3. @OneToMany+@JoinColumn

When a collection is mapped using these two annotations, Hibernate doesn't generate a join table. Envers, however, has to do this, so that when you read the revisions in which the related entity has changed, you don't get false results.

To be able to name the additional join table, there is a special annotation: @AuditJoinTable, which has similar semantics to JPA's @JoinTable.

One special case are relations mapped with @OneToMany+@JoinColumn on the one side, and @ManyToOne+@JoinColumn(insertable=false, updatable=false) on the many side. Such relations are in fact bidirectional, but the owning side is the collection (see alse here).

To properly audit such relations with Envers, you can use the @AuditMappedBy annotation. It enables you to specify the reverse property (using the mappedBy element). In case of indexed collections, the index column must also be mapped in the referenced entity (using @Column(insertable=false, updatable=false), and specified using positionMappedBy. This annotation will affect only the way Envers works. Please note that the annotation is experimental and may change in the future.

Community
  • 1
  • 1
James Gan
  • 6,988
  • 4
  • 28
  • 36