Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save david-developer-play/552ac9ce03dc8752464231e5eae95b59 to your computer and use it in GitHub Desktop.
Save david-developer-play/552ac9ce03dc8752464231e5eae95b59 to your computer and use it in GitHub Desktop.
Envers auditing of changes in children
public List<ChildChangeAtRevision> getAllChildChangesWithMetadata(Long parentId) {
AuditReader reader = AuditReaderFactory.get(entityManager);
// 1. Get revisions from parent collection changes
List<Number> parentRevs = reader.createQuery()
.forRevisionsOfEntity(Parent.class, false, true)
.add(AuditEntity.id().eq(parentId))
.add(AuditEntity.property("children").hasChanged())
.getResultList();
// 2. Get revisions from child field changes
List<Number> childRevs = reader.createQuery()
.forRevisionsOfEntity(Child.class, false, true)
.add(AuditEntity.property("parent").id().eq(parentId))
.getResultList();
// 3. Merge & deduplicate
Set<Number> allRevs = new TreeSet<>();
allRevs.addAll(parentRevs);
allRevs.addAll(childRevs);
// 4. Build result
List<ChildChangeAtRevision> results = new ArrayList<>();
for (Number rev : allRevs) {
Parent parentAtRev = reader.find(Parent.class, parentId, rev);
if (parentAtRev != null) {
CustomRevisionEntity revEntity = reader.findRevision(CustomRevisionEntity.class, rev);
results.add(new ChildChangeAtRevision(
rev,
revEntity.getRevisionDate(),
revEntity.getUsername(),
new ArrayList<>(parentAtRev.getChildren())
));
}
}
return results;
}
public record ChildChangeAtRevision(
Number revision,
Date timestamp,
String username,
List<Child> children
) {}
==============================================================================================================================
// Regular hibernate envers
public List<RuleChangeAtRevision> getAllRuleAndCommentChanges(Long ruleId) {
AuditReader reader = AuditReaderFactory.get(entityManager);
// 1. Revisions where Rule entity or its comments collection changed
List<Number> ruleRevs = reader.createQuery()
.forRevisionsOfEntity(Rule.class, false, true)
.add(AuditEntity.id().eq(ruleId))
.add(AuditEntity.or(
AuditEntity.property("comments").hasChanged(),
AuditEntity.revisionType().ne(RevisionType.DEL) // include if Rule was updated
))
.getResultList();
// 2. Revisions where any Comment assigned to this Rule changed
List<Number> commentRevs = reader.createQuery()
.forRevisionsOfEntity(Comment.class, false, true)
.add(AuditEntity.property("rule").id().eq(ruleId))
.getResultList();
// 3. Merge and deduplicate
Set<Number> allRevs = new TreeSet<>();
allRevs.addAll(ruleRevs);
allRevs.addAll(commentRevs);
// 4. Fetch Rule and Comment states for each revision
List<RuleChangeAtRevision> results = new ArrayList<>();
for (Number rev : allRevs) {
Rule ruleAtRev = reader.find(Rule.class, ruleId, rev);
if (ruleAtRev != null) {
CustomRevisionEntity revEntity = reader.findRevision(CustomRevisionEntity.class, rev);
// Optionally deep-copy comments if you need to filter or prevent lazy issues
List<Comment> comments = ruleAtRev.getComments() != null
? new ArrayList<>(ruleAtRev.getComments())
: List.of();
results.add(new RuleChangeAtRevision(
rev,
revEntity.getRevisionDate(),
revEntity.getUsername(),
ruleAtRev,
comments
));
}
}
return results;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment