Search code examples
javahibernateormaudithibernate-envers

How to configure Hibernate Envers to avoid certain collections (join tables) in entity revision queries


I am using Hibernate Envers 4.2, I want to fetch the revisions of entity with only details from some of the collections in the Entity.

But I could see hibernate queries fired for all collections in the Entity causing performance problems.

Also could not use @NotAudited annotation for the collections to avoid in this particular query as the auditing is desired in other scenarios for those collections.

For example, if my Audited Entity has these two joins as collections. But I want the query getting revisions of my entity to fetch only address information and ignore Order information, is it possible? I don't want to annotate Order information with @NotAudited since the history information may be desired in other scenarios.

@ManyToOne
@JoinColumn(name="ADDR_ID")
public Address getAddress() { return address; }

@OneToMany
@JoinColumn(name="CUST_ID") 
public Set<Order> getOrders() {return orders;}

Solution

  • As in this Hibernate documentation example, If I have a Customer with an Address association:

    @Audited( withModifiedFlag = true )
    @Entity(name = "Customer")
    public class Customer {
    
        ...
    
        @ManyToOne(fetch = FetchType.LAZY)
        private Address address;
    
    }
    

    and I query the revisions using this query:

    List<Customer> customers = AuditReaderFactory
    .get( entityManager )
    .createQuery()
    .forRevisionsOfEntity( Customer.class, false, true )
    .add( AuditEntity.id().eq( 1L ) )
    .add( AuditEntity.property( "lastName" ).hasChanged() )
    .getResultList();
    

    Envers only queries for Customers, not Address:

    select
        c.id as id1_3_0_,
        c.REV as REV2_3_0_,
        defaultrev1_.REV as REV1_4_1_,
        c.REVTYPE as REVTYPE3_3_0_,
        c.REVEND as REVEND4_3_0_,
        c.created_on as created_5_3_0_,
        c.createdOn_MOD as createdO6_3_0_,
        c.firstName as firstNam7_3_0_,
        c.firstName_MOD as firstNam8_3_0_,
        c.lastName as lastName9_3_0_,
        c.lastName_MOD as lastNam10_3_0_,
        c.address_id as address11_3_0_,
        c.address_MOD as address12_3_0_,
        defaultrev1_.REVTSTMP as REVTSTMP2_4_1_
    from
        Customer_AUD c cross
    join
        REVINFO defaultrev1_
    where
        c.id = ?
        and c.lastName_MOD = ?
        and c.REV=defaultrev1_.REV
    order by
        c.REV asc
    
    -- binding parameter [1] as [BIGINT]  - [1]
    -- binding parameter [2] as [BOOLEAN] - [true]
    

    Unless you navigate associations like this:

    AuditQuery innerJoinAuditQuery = AuditReaderFactory
    .get( entityManager )
    .createQuery()
    .forEntitiesAtRevision( Customer.class, 1 )
    .traverseRelation( "address", JoinType.INNER );
    

    Hibernate Envers should not include them in the SQL revision query.