spring-boothibernatehibernate-envers

Hibernate Envers Audit Join Table defenition


I want to add history to my entities and I am playing arround with hibernate Envers.

I have defined Handbook and Chapter classes with the coresponding 5 tables: HANDBOOK, HANDBOOK_AUD, CHAPTER, CHAPTER_AUD and REVINFO.

If there is no connection between the 2 entities, everithing works fine, but when I add oneToMany relationship for HANDBOOK and CHPATER the application fails to start because of missing HANDBOOK_CHAPTER_AUD table.

Thinking about it is absolutely fine to have that JoinTable, but the problem is how should define it.

Handbook entity:

@Entity
@Audited
@Getter
@Setter
@NoArgsConstructor
public class Handbook {

    @Id
    @SequenceGenerator(name = "HANDBOOK_ID_SEQUENCE", sequenceName = "HANDBOOK_ID_SEQUENCE", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "HANDBOOK_ID_SEQUENCE")
    private Long id;
    private String title;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "HANDBOOK_ID")
    @AuditJoinTable(name = "REV_HANDBOOK_CHAPTER")
    private Set<Chapter> chapters;

}

Chapter entity:

@Entity
@Audited
@Getter
@Setter
@NoArgsConstructor
public class Chapter {

    @Id
    @SequenceGenerator(name = "CHAPTER_ID_SEQUENCE", sequenceName = "CHAPTER_ID_SEQUENCE", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CHAPTER_ID_SEQUENCE")
    private Long id;
    private String name;

    @Column(name = "HANDBOOK_ID")
    private Long handbookId;

}

Tables deffinition:

<createTable tableName="REVINFO">
    <column name="rev" type="integer">
        <constraints primaryKey="true" nullable="false"/>
    </column>
    <column name="revtstmp" type="bigint"/>
</createTable>

<!-- Hibernate Envers need this seq exact to increase the revision number for versioned entities-->
<createSequence sequenceName="HIBERNATE_SEQUENCE"
                startValue="1"
                incrementBy="1"/>

<createTable tableName="HANDBOOK">
    <column name="ID" type="bigint">
        <constraints primaryKey="true" nullable="false"/>
    </column>
    <column name="TITLE" type="varchar2(128 char)"/>
</createTable>

<createTable tableName="REV_HANDBOOK">
    <column name="ID" type="bigint"/>
    <column name="TITLE" type="varchar2(128 char)"/>

    <column name="REV_ID" type="integer">
        <constraints foreignKeyName="FK_HANDBOOK_REV"
                    references="REVINFO(REV)"/>
    </column>
    <column name="REV_TYPE" type="smallint"/>
</createTable>

<!--    CHAPTER TABLES    -->
<createTable tableName="CHAPTER">
    <column name="ID" type="bigint">
        <constraints primaryKey="true" nullable="false"/>
    </column>
    <column name="NAME" type="varchar2(128 char)"/>
    <column name="HANDBOOK_ID" type="integer">
        <constraints foreignKeyName="FK_CHAPTER_HANDBOOK_ID"
                     references="HANDBOOK(ID)"/>
    </column>
</createTable>

<createTable tableName="REV_CHAPTER">
    <column name="ID" type="bigint"/>
    <column name="NAME" type="varchar2(128 char)"/>
    <column name="HANDBOOK_ID" type="integer">
        <constraints foreignKeyName="FK_CHAPTER_AUD_HANDBOOK_ID"
                     references="HANDBOOK(ID)"/>
    </column>

    <column name="REV_ID" type="integer">
        <constraints foreignKeyName="FK_CHAPTER_REV"
                     references="REVINFO(REV)"/>
    </column>
    <column name="REV_TYPE" type="smallint"/>
</createTable>

NOTE: I have edited some namings according to the hibernate envers documentation:

  org:
    hibernate:
      envers:
        audit_table_prefix: REV_
        audit_table_suffix: ~  # No suffix
        revision_field_name: REV_ID
        revision_type_field_name: REV_TYPE

Solution

  • I have found out a sollution based on the series of errors hibernate gave me after running the code. Here is how I defiend the revision join table:

        <createTable tableName="REV_HANDBOOK_CHAPTER">
            <column name="ID" type="bigint"/>
            <column name="REV_ID" type="integer">
                <constraints foreignKeyName="FK_REV_HANDBOOK_CHAPTER_REV"
                             references="REVINFO(REV)"/>
            </column>
            <column name="HANDBOOK_ID" type="bigint">
                <constraints foreignKeyName="FK_REV_HANDBOOK_CHAPTER_HANDBOOK"
                             references="HANDBOOK(ID)"/>
            </column>
            <column name="REV_TYPE" type="smallint"/>
        </createTable>