5 Replies Latest reply on May 28, 2013 5:57 AM by anthonyb

    [RESOLVED] Hibernate-Envers 3.6.10-Final with ValidityAuditStrategy throws NonUniqueObjectException

    anthonyb

      Hello,

       

      I'm working on an application based on Hibernate-Envers 3.6.10-Final where we have chosen to use the strategy ValidityAuditStrategy, due to the very critical performance issues of the default strategy we have encountered.

       

      However, during the lazy loading entities process, the "find" method which should returns only the last revision of one entity can bring more than one result.

       

       

      I have managed to identify where the problem occured. This is inside the AuditReaderImpl class, in the find(Class<T>, String, Object, Number) method:

      result = createQuery().forEntitiesAtRevision(cls, entityName, revision).add(AuditEntity.id().eq(primaryKey)).getSingleResult();

      I have changed the "getSingleResult()" by a "getResultList().get(0)" to see if the global process was working and this was fine (except the first value may not be the right one). Otherwise, the NonUniqueObjectException is thrown.

       

      It seems that the query is only based on the primary key "id" and does not take into account other primary keys of the related table. In our audit tables, there is also the "REV" colmun in the primary key, and sometimes other columns. If we take only the "id", there are duplicates but if we considered the REV column, our table contains no duplicates entries.

       

       

      Here is how the related entity is configured:

      @MappedSuperclass
      public abstract class GenericConfiguration extends LockableModel {
      
      
          //Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
          @Required
          //everyone but REMOVE
          @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.DETACH, CascadeType.MERGE})
          @JoinColumn(name = "applicationBranch", nullable = false)
          public ApplicationBranch applicationBranch;
      
      
          @ManyToMany(cascade = CascadeType.ALL)
          @Audited
          public List<PropertyValue> properties; // FIXME ABN: Le fait que ça soit auditer fait perdre du temps

      The lazy entity example here is "properties". With the default strategy, this entity was correctly loaded, but with the critical performance issues I've mentionned.

       

      Then the PropertyValue entity class:

      @Audited
      @Entity
      @Table(name="PVALUE")
      public class PropertyValue extends Model implements Comparable {

       

      Is there anything that I should do or check to make this strategy work fine on my application ? Do you need other information to analyze my problem ?

       

      I think I have correctly populated the REVEND column and I have succeded in seeing a hibernate query containing this REVEND column, whereas with the default strategy this column was never used.

       

      Here is the only configuration regarding this new audit strategy:

      <property name="org.hibernate.envers.audit_strategy" value="org.hibernate.envers.strategy.ValidityAuditStrategy" />

       

       

      Thank you in advance.

      Regards,

        • 1. Re: Hibernate-Envers 3.6.10-Final with ValidityAuditStrategy throws NonUniqueObjectException
          adamw

          Hello,

           

          there should only be one result. The query does include constraints on REV/REVEND, these are added by the "forEntitiesAtRevision" call.

          Do you have the end query?

           

          Maybe the REVEND values are wrong?

          If an entity with id 22 was modified at revisions 5, 10 and 13, the values in the DB should be (id, REV, REVEND):

          (22, 5, 9)

          (22, 10, 12)

          (22, 13, NULL)

           

          Is that what you are seeing?

           

          Adam

          • 2. Re: Hibernate-Envers 3.6.10-Final with ValidityAuditStrategy throws NonUniqueObjectException
            anthonyb

            Hello Adam,

             

            Thank you very much for your answer, I think this is what I missed.

             

            Actually, I put in the "REVEND" column the lastest revision. In your example, I would have put:

            (22, 5, 13)

            (22, 10, 13)

            (22, 13, NULL).

             

            Which is wrong regarding your answer and could explain why I can retrieve more than one result.

             

            I have misundersood how the REVEND column worked, as I had to fill the column manually during the migration of strategies. At least there is something to do to make it automatically by the Enevers module ?

             

            Could you confirm that the REVEND is always REV-1 of the next line in the revision order, like in your example ? I must be sure that my data is correct to make the migration in production when everything will be ok. Well, I think this is right as it means in your example "data with id 22 from the revision 5 to 9 was the same, then from 10 to 12 was the same, then changed at 13". This is clear now.

             

            Thank you.

             

            Regards,

            Anthony

            • 3. Re: Hibernate-Envers 3.6.10-Final with ValidityAuditStrategy throws NonUniqueObjectException
              adamw

              There's no automated tool unfortunately.

               

              In fact the number should be:

              (22, 5, 10),

              (22, 10, 13),

              (22, 13, NULL)

               

              (that is, REVEND is exclusive).

               

              Adam

              1 of 1 people found this helpful
              • 4. Re: Hibernate-Envers 3.6.10-Final with ValidityAuditStrategy throws NonUniqueObjectException
                anthonyb

                Ok, thanks. I will change my SQL update script to take that into account.

                 

                This is only to make existing lines as they would have been filled using the ValidityAuditStrategy from the beginning.

                 

                Thank you very much for your help.

                 

                Regards,

                Anthony

                • 5. Re: Hibernate-Envers 3.6.10-Final with ValidityAuditStrategy throws NonUniqueObjectException
                  anthonyb

                  Just for information, here is the SQL query that I've used to update correctly all REVEND columns, according to the last Adam's reply:

                   

                  UPDATE table_to_update a

                   

                  INNER JOIN

                       (select

                            z.id,

                            z.REV,

                            (select x.REV from table_to_update x

                                 where z.id = x.id and z.REV < x.REV

                                 order by x.REV asc limit 1) AS nextREV

                             from table_to_update z)

                  b ON b.id = a.id and a.REV = b.REV

                   

                  SET REVEND = b.nextREV

                  1 of 1 people found this helpful