6 Replies Latest reply on Nov 1, 2006 9:07 PM by gavin.king

    EntityHome silently discards updates after errors

      In the framework, I'm trying to enforce optimistic locking and a unique constraint on the "name" attribute. For optimistic locking, there's not a lot I can do except kick them out (they can always open a new window and use their back button to copy their changes and merge them in). For name conflicts, I thought to add a message and let them try something else.

      Here's the code:

       @End @Transactional @Override
       public String update() {
       getInstance().setUpdatedOn(new Date());
       try {
       return super.update();
       } catch (OptimisticLockException e) {
       facesMessages.add("#{messages.staleEditRule}");
       return "aborted";
       } catch (EntityExistsException e) {
       facesMessages.add("name", "#{messages.errNameExists}");
       return null;
       } catch (RuntimeException e) {
       facesMessages.add(e.toString());
       return null;
       }
       }
      


      Only problem is, this appears to work -- you correct the name, hit update, your changes appear to take, you're back in the view screen -- but when you next view the entity you edited, you find your changes never actually took.

      I think I understand why this is happening -- the session is no longer valid after an exception -- but there's no indication even in log messages that this has happened, and the update was just silently dropped.

      So I have two questions:

      1) Is the lost update detectable somehow? I feel like EntityManager should have screamed at me for trying to update again after the exception, but it gave nary a peep.

      2) How do I gracefully recover from errors on update and reset the entityManager so further updates can succeed? Should I make the unique constraint a validator instead? Enforcing unique constraints must be a FAQ for Hibernate, but I haven't found an answer yet.



        • 1. Re: EntityHome silently discards updates after errors
          gavin.king

          1) yes, probably EM should have thrown an exception - ask about this in the Hibernate or EJB3 forums
          (2) The best way to handle this is to check to see if an instance with the same name exists in the database *first*, rather than trying to do something that you know is possibly going to violate a constraint.

          • 2. Re: EntityHome silently discards updates after errors

            I should probably clarify, the exception gets thrown the first time, but the second update appeared to succeed when in fact it silently dropped. I've done quite a bit of rearranging now, and haven't reproduced the problem.

            As for checking the unique constraint by hand before possibly violating it, I suppose I can live with that, even if it violates DRY. The how of that however is still a bit elusive -- checking it in the action method seems to come too late, because the model values have already been updated, and I get dumped into the debug page due to constraint violations while accessing other components -- namely a datamodel that lists related entities, one of which might actually have the conflicting name.

            I tried using a separate entityManager so I wouldn't be reading the current transaction's dirty data, but that didn't pan out either -- the datamodel just ended up null.

            • 3. Re: EntityHome silently discards updates after errors

              Actually it looks like simply using another EntityManager anywhere in my action bean caused a completely _different_ component (ruleTypes) in the action bean to not be injected. Same result whether I injected it with @PersistenceContext or created it by hand with new EntityManagerFactory().createEntityManager(). I guess using multiple entity managers is verboten.

              Things just shouldn't be so difficult. I can't be the first person in the world who has ever had to enforce a uniqueness constraint with JPA.





              • 4. Re: EntityHome silently discards updates after errors

                I still can't explain the mysterious breakage that started when using another entityManager, but it went away when I switched from a javabean to a SFSB, something I was going to do eventually anyway. I was still seeing dirty data, but I found it was the database I was using -- it looks like HSQLDB only supports Read Uncommitted isolation (it really shouldn't be called isolation at all). Obviously I was going to switch out DB's too .. I guess the moral of the story is to develop for the platform you expect to use sooner rather than later.

                If I ever puzzle this out, I'll try submitting a wiki as an example application -- it's the simplest real-world app I can think of where you'd want uniqueness and concurrency control with "retry" options in the UI.

                • 5. Re: EntityHome silently discards updates after errors

                  I'm a dunderhead -- not that this is a big surprise to anyone. It had nothing to do with transaction isolation levels, and everything to do with needing to set flushMode=MANUAL when beginning the conversation. Once I did that, everything works as expected, and entities aren't flushed until I actually tell it to.

                  I kludged a call to Conversation.instance().changeFlushMode(MANUAL) in a @Create method on RuleHome, because it does have to be available to non-faces requests (quite a lot of my app has to be RESTful). I don't know if there's any more elegant way to do it, since my tinkering with pages.xml wasn't too successful.


                  • 6. Re: EntityHome silently discards updates after errors
                    gavin.king

                    Your kludge is unnecessary. You should be able to use:

                    @Create @Begin(flushMode=FlushMode.MANUAL)
                    public void create() {}



                    If this does not work, please let me know, because it would be a bug in Seam.