4 Replies Latest reply on Nov 8, 2010 3:36 PM by Adam Warski

    Attaching revision details entity to REVINFO

    Scott Mueller Newbie

      In our current envers-like system, we have an entity called ChangeOrigin that we associate with every revision.  Similar to REVINFO except ChangeOrigin can span multiple transactions.  It basically contains an Author entity, IP address, time change was requested, how the change was made (api, web, flash widget, other methods), etc.

       

      So we have a custom Revision entity with an AuditListener.  In the AuditListener, we simply set the changeOrigin entity on the revisionEntity from a ThreadLocal object:

      revisionEntity.setChangeOrigin(revisionData.getChangeOrigin());

       

      Now the problem is we get very strange behavior when the Author is updating himself...  Basically, there's a changeOrigin.getAuthor() that returns a Person entity.  Sometimes the author wants to update his Person.  So we used to load the author in a different transaction, so the changeOrigin.getAuthor() would be a detached Person.  That wasn't a problem.  Now it is.  So we tried setting changeOrigin.setAuthor(new DummyPerson(sameIdOfAuthor)).  That has the same odd behavior.  changeOrigin.setAuthor(null) works perfectly fine except, of course, we have no author info!  So there are 2 options as we see them:

      • Retrieve author in the web tier, set in the ThreadLocal for the ChangeOrigin and whenever saving any entity in the manager/transaction tier, look at the ThreadLocal for the ChangeOrigin and make sure if getAuthor() is being updated, then call changeOrigin.setAuthor(currentPersistentPerson).
      • Subclass an AuditStrategy and override some methods to get access to hibernate directly and do our checks there.

       

      I really don't like the first option as we have to remember to do that properly every time or experience weird, and sometimes difficult to detect, hibernate session behavior.  Plus it makes our code ugly as we now have to deal with ChangeOrigins instead of having them automatically handled in the web tier.  The 2nd option, is this advisable?

       

      This must be a pretty common scenario, wanting to link an Author entity to the revision, right?  And you can't load Author twice with hibernate in case you are also making changes to the Author entity, BY the author....

        • 1. Re: Attaching revision details entity to REVINFO
          Adam Warski Master

          Why using a detached Author is a problem? What kind of cascades do you have for revEntity.changeOrigin and changeOrigin.author? Is the change origin already persisted when you set it on the rev entity?


          Adam

          • 2. Re: Attaching revision details entity to REVINFO
            Scott Mueller Newbie

            Why a detached Author is a problem is beyond me...  Very weird things happen when I have a detached author, seemingly random and unrelated parts of our entity hierarchy get set to null, but no exceptions are ever thrown..

             

            The ChangeOrigin is NOT persisted when setting it on the rev entity.  Persisting the rev entity cascades the saving to the ChangeOrigin.  on revEntity.changeOrigin, cascading is set to CascadeType.ALL.  On changeOrigin.author, cascading is not set at all.

             

            BTW, having a detached Author set on changeOrigin is not the only way to have our weird problems.  Loading the Author using HQL in the same transaction also causes the exact same problems.  The issue is specifically loading the author for the changeOrigin and loading the same person as part of the entity you're updating separately.  Instead what we have to do to avoid problems is:

             

            if (changeOrigin.getAuthor().getId().equals(personWeAreUpdating.getId()))

                changeOrigin.setAuthor(personWeAreUpdating);

            • 3. Re: Attaching revision details entity to REVINFO
              Sviatoslav Reentenko Newbie

              You could put ChangeOrigin required data in thread context using filter or request listener. Later, when saving entity you should use custom envers strategy based on default strategy or validity one. In this strategy class use just regular Hibernate session to lookup Author by provided data and construct new ChangeOrigin object. I'm not sure about using custom revision listener for access to Hibernate session.

              • 4. Re: Attaching revision details entity to REVINFO
                Adam Warski Master

                If there is not cascade onto the author the attached/detached shouldn't be a difference if I'm not mistaken. Anyway, I would first investigate why this causes problems (a detached author), as it really shouldn't and it's quite weird - possibly you have a bug in another area, or maybe some weird bug in Envers, who knows


                Adam