Search code examples
hibernatehibernate-envers

Hibernate Envers Audit table with no suffix


I'm trying to save my audits table in another schema but keeping the tables with the same name of the audited table. I had no problem changing the suffix or using another schema, but when I set the suffix to a empty string I'm getting the following error:

Caused by: org.hibernate.DuplicateMappingException: Duplicate class/entity mapping com.logique...User

I'm guessing this error is happening because I have two tables with the same name (but in different schemas), I set the "org.hibernate.envers.default_schema" and the "hibernate.default_schema" parameter correctly, I was not expecting this problem.


Solution

  • When Hibernate performs its metadata collection process, it first reads all your annotated entity classes and registers each of them by name. Additionally, as Envers processes its metadata and provides that information back to Hibernate, Hibernate will then in turn register each of those audited entities by name as well.

    The issue here is that without providing a suffix or prefix, Hibernate sees the mappings from Envers as the already registered entity name because without the prefix/suffix, they're named exactly the same as the source entity they're generated from, causing this error.

    org.hibernate.DuplicateMappingException: Duplicate class/entity mapping
    

    There is a workaround, but it can be tedious depending on the number of audited entities you may have. I have tested this on 5.x and I likely suspect this should work on 4.3.x.

    1. Set either the audit_table_prefix or audit_table_suffix configuration properties. This is a must because this is what will force the metadata from Envers to be uniquely named persistable objects to Hibernate. Without doing this, you'll continue to get the duplicate mapping error from above.
    2. For each audited entity, explicitly add an @AuditTable annotation where you specifically set the audit table name to be identical to the the name being generated for your entity, whether it is based on the class name or an existing @Table with a name attribute.

    So as an example:

    @Entity
    @Table(name = "my_table")
    @AuditTable("my_table")
    public class MyTableEntity {
      /* stuff */
    }
    

    So with this configuration, you will be able to have your Envers tables in one schema, the main entity tables in another, and both schemas have their tables names be identical.

    Hope this helps.