I'm using Hibernate with Envers, 4.3.6 FINAL. I have set up auditing using the annotations, and all of my audit tables have been created and are being populated correctly when I save information in my application. One of my audited entities has a mapping table to additional entities, with a @ManyToMany configuration.
Employer -> Designations
The employer can have 0 to n Designation entities associated with it. The mapping table is standard, just having two columns, a foreign key to the Employers table and a foreign key to the Designations table. Envers created an auditing table for this mapping table and records are appropriately recorded, with inserts or deletes entered with the same REV as the Employer when the Employer is edited.
What I'm trying to do now is retrieve the audit information from the database so I can present it for reporting purposes. Retrieving the list of revisions for my Employer is working and the state of the Employer for a given revision is accurate. What I haven't been able to figure out is how to retrieve the audits for the mapping table. I have no actual entity for these pairings. They are put together using the javax.persistence.JoinTable annotation. As such, there's no record for an entity in my REVCHANGES table (I'm setting org.hibernate.envers.track_entities_changed_in_revision to true). Looking at the database, there are records for my EmployerDesignations mapping table and the corresponding EmployerDesignations_AUD audit table, but I don't know how to retrieve these audit records nor how to even know when they have been changed for a given revision.
How can the audit history for a mapping table be retrieved?
Employer class:
@Entity
@DynamicInsert
@DynamicUpdate
@SelectBeforeUpdate
@Table(name="EMPLOYERS")
@Audited
public class Employer implements Serializable {
//All other fields omitted for brevity
...
private List<Designations> designations;
@ManyToMany
@JoinTable(name = "EMPLOYERDESIGNATIONS",
joinColumns = { @JoinColumn(name = "FK_EMPLOYER", nullable = false) },
inverseJoinColumns = { @JoinColumn(name = "FK_DESIGNATION", nullable = false) })
public List<Designations> getDesignations() {
return designations;
}
public void setDesignations(List<Designations> designations) {
this.designations= designations;
}
}
Designation class:
@Entity
@DynamicInsert
@DynamicUpdate
@SelectBeforeUpdate
@Table(name="DESIGNATIONS")
@Audited
public class Designation implements Serializable {
//All other fields omitted for brevity
...
private List<Employer> employers;
@ManyToMany
@JoinTable(name = "EMPLOYERDESIGNATIONS",
joinColumns = { @JoinColumn(name = "FK_DESIGNATION", nullable = false) },
inverseJoinColumns = { @JoinColumn(name = "FK_EMPLOYER", nullable = false) })
public List<Employer> getEmployers() {
return employers;
}
public void setEmployers(List<Employer> employers) {
this.employers= employers;
}
}
Test Code for audit data retrieval:
List<Number> revisions = reader.getRevisions(Employer.class, employerId);
System.out.println(revisions);
for (Number revisionNum : revisions) {
Employer employer = reader.find(Employer.class, employerId, revisionNum);
System.out.println(employer);
}
All you need to do is to retrieve the Employer
instance and then simply access the getter for the association and whatever state that associated had when the entity was audited will be made available automatically.
If we assume the first operation in the Envers environment was you creating an Employer
and associating it with two Designation
entities via your join, then when you fetch the Employer
instance for revision 1, the collection would have two elements.
Later on in transaction 2, you modify Employer
and you remove one Designation
and add a new Designation
to the entity, then when you fetched the Employer
at revision 2, it would still contain two Designation
entity instances, but those instances would be the one that remained from the first revision and the second which you added as part of the second revision.