5 Replies Latest reply on Jul 17, 2011 2:03 AM by adamw

    Custom RevisionEntity with changed fields

    higs

      Hi all, very new to Persistence/Hibernate/Envers, but I think I'm making pretty good headway.  I've currently setup Hibernate and Envers to audit a personnel records type of database/application, and I'm even using a semi-custom RevisionEntity that captures the username (from the System login), and allocates for another timestamp for when a Form is generated based on the revision.  However, I'm wondering if it's possible to do a comparison of the current revision and the new revisionEntity, to identify the fields of the entity that have changed, and store an Array of those Field objects in the custom RevisionEntity?

       

      I am currently working around this by making a Array of Field objects part of the main objects that I'm using, but that doesn't seem like it's the best place to store a "log" of changed fields.  It seems like it's best put in the custom RevisionEntity object.

       

      Here's my current implimentation:

      {code}

      @Entity

      @RevisionEntity(ManningListener.class)

      public class ManningRevEntity extends DefaultRevisionEntity

           private String username;

           private long formTimestamp;

      {code}

       

      and the custom listener:

      {code}

      public class ManningListener implements RevisionListener{

           public void newRevision(Object revisionEntity){

                ManningRevEntity rev = (ManningRevEntity)revisionEntity;

                rev.setUsername(System.getProperty("user.name"));

           }

      }

      {code}

       

      I read the documentation for Envers and it alluded to the possibility of using getCurrentRevision and AuditReader, but how do I do that?

       

      THanks!

        • 1. Re: Custom RevisionEntity with changed fields
          adamw

          Hmm, so first thing is that the revision entity stores just the meta-data of a revision: that is a transaction in which some entities have been changed. Now, you probably want to compare two revisions of an entity to see what changed? The simplest way is to grab the two objects and compare them field by filed . You can get a history of an entity using the audit reader. Not sure if that meets your requirements?

           

          Adam

          • 2. Re: Custom RevisionEntity with changed fields
            higs

            Adam,

             

            First off, thanks for the reply, and sorry for the late reply (was on vacation).

             

            Just a trivial notion, but couldn't you consider "the fields of the entity that were changed in this revision" as Meta-data for the revision?

             

            Secondly, I've been attempting to do manually compare two revisions, and it does seem to work sometimes, however I think I'm running into problems with "traversing" a list of revisions for an entity.  Currently, I'm using the following:

             

            {code}

            ArrayList<Number> revs = new ArrayList<Number>(reader.getRevisions(Employee.class, emp.getEmpid()));

            for(int i=revs.size()-1; i>0; i--){
                            Employee revEmp = reader.find(Employee.class, emp.getEmpid(), revs.get(i));
                            Employee nextRev = reader.find(Employee.class, emp.getEmpid(), revs.get(i-1));

                           ** DO COMPARISON ***

            }

            {/code}

             

            WHen I wrote this, I was under the impression that revs (the list of revisions) would be  something like 1,2,3,4,5, when in reality its 1,3,7,8,10,etc depending on how it was edited.

             

            Is there a better way to do traverse an array of revisions for an enity?

             

            Or better yet, is there a better way to acheive what I'm working at?

             

            THanks for any guidance/pointers!

             

            Jeremy

            • 3. Re: Custom RevisionEntity with changed fields
              sebp

              Hi Jeremy,

               

              for traversing the entities you could use AuditReader.forRevisionsOfEntity() E.g.:

               

              List<Object[]> results = reader.createQuery()
                              .forRevisionsOfEntity(Employee.class, false, true)
                              .add(AuditEntity.id().eq(emp.getEmpid()))
                              .getResultList();
              

               

              For each revision an object array with three objects is returned containing the RevisionEntity, the RevisionType and the Employee in that order. This way you get all the data you need in your loop with one AuditReader call.

              The comparison of the employee fields to find the changes from one revision to another has to be done manually, I think.

              • 4. Re: Custom RevisionEntity with changed fields
                higs

                Thanks guys.  I think I got it working.  Here is what I used: (How do you insert code properly?!)

                ArrayList<Number> revs = new ArrayList<Number>(reader.getRevisions(Employee.class, emp.getEmpid()));
                        this.revisionPane.removeAll();
                        for(int i=revs.size()-1; i>0; i--){
                            Employee revEmp = reader.find(Employee.class, emp.getEmpid(), revs.get(i));
                            Employee nextRev = reader.find(Employee.class, emp.getEmpid(), revs.get(i-1));

                 

                Not sure how this differs from Sebastian's process.

                 

                But from there, I then run a comparison method that uses reflection on the object to check each field against the revision at the field level.  Does the trick for me, plus I don't have to re-write the comparision method if I modify the fields of the object (add/delete, etc).

                 

                Thanks again for the help guys.  I have a new question to ask and I'll start a new threat.

                 

                Jeremy

                • 5. Re: Custom RevisionEntity with changed fields
                  adamw

                  To summarize:

                   

                  Just a trivial notion, but couldn't you consider "the fields of the entity that were changed in this revision" as Meta-data for the revision?

                   

                  That's a proposed feature, one that I haven't yet implemented, but it makes much sense. Although it's possible to get the information now, just as you do, but with a little more effort.

                   

                  Not sure how this differs from Sebastian's process.

                   

                  Sebastian uses less queries (one), instead of multiple DB queries. But apart from that, funcationally the solutons are equivalent.


                  Adam