I have two audited entities, A and B. Entity A holds a collection of entity B (annotated as One-to-many relationship). When inserting a new instance of A into the database, all rows of A and B are at the same revision (let's say revision 1). Then, there is an update on A which only affect the instances of entity B. So after the update, the entity A is still at revision 1, whereas the entities of B are at revision 2 (including a MOD entry in the audit table). In Revision 3, the entity A is deleted. Because the collection of entity B is annotated with @Cascade, the entities B belonging to A are deleted as well.
Given this scenario, how to I create an audit query with Envers that gets an instance of entity A with the updated entities B of revision 2? When I query for all revisions of entity A, I either get the deleted entity of A which holds no entities of B (revision 3), or I get A of revision 1 which holds B entities of revision 1, too.
Using Hibernate 3.6, if that helps.
If you read entity A at revision 2, you will get the right data.
There is no way currently to get a list of revisions where an entity or related entities changed (as is your case - rev 2 is a change only in B, not in a).
I solved a similar problem by adding a hidden lastUpdated date field on my equivalent of your A entity.
@Entity
public class A {
private Date lastModified;
@OneToMany(mappedBy = "a", cascade = CascadeType.ALL )
private List<B> blist;
public void touch(){
lastModified=new Date();
}
}
Then in the related entities (like you B field), I added the following :
public class B {
@ManyToOne
private A a;
@PreUpdate
public void ensureParentUpdated(){
if(a!=null){
a.touch();
}
}
}
This ensures that a revision is added to A whenever a revision is added to B even though it requires custom code in many entities.
In your case this will ensure that A's history actually contains the revisions of B. this way you only need one query to get all the revisions for the whole A, Bs graph
In Hibernate we could control the loading of children by specifying lazy. So, you need to add the below line to your class definition in hibernate configuration for it to load all the associations in both read/write cases.
<cache usage="read-write"/>
If you have marked CacheMode.REFRESH then it will write items to the second-level cache. Do not read from the second-level cache.
If you don't have issues in loading the children at the time of parent you could turn of lazy which will return the updated information.