4 Replies Latest reply on Nov 17, 2006 6:07 AM by hoeft

    UserTransactions and merge

    klaus_erber

      Hello,

      I think I have some understanding problems with UserTransactions, detaching and merging.

      Why does the following code don't update the entity?

      UserTransaction ut = sessionContext.getUserTransaction();
      MyEntity a = em.find(MyEntity.class, Long.valueOf(1));
      ut.commit();
      
      ut = sessionContext.getUserTransaction();
      em.merge(a);
      a.setName("FOO2");
      ut.commit();
      


      (JBoss-4.0.5.GA)

        • 1. Re: UserTransactions and merge
          hoeft

          You mixed the lines.

          You must write:

           (...)
           a.setName("F002");
           em.merge(a);
           (...)
          


          If you call persist or merge on an entity manager, the entity manager recognizes the state of the entities at this time. Changes which are made later to the entities doesn't bother him if they aren't followed by a merge operation. If the entity manager leaves the scope of a transaction, he persists the entitie states to the database.

          Thats the reason why your entity isn't updated.

          Best regards
          Meinert


          • 2. Re: UserTransactions and merge
            hoeft

            I have forgotten something: You forgot to mark the boundries of the transaction scope correctly. The transaction scope is importend, because the entitymanager persists the entities if he leaves the transaction scope. The boundries are marked by the begin() and commit() method. You forgot the begin method.

            The corrected code:

             (...)
             ut.begin(); //start of the transaction scope
             a.setName("F002");
             em.merge(a) // better: a = em.merge(a)
             ut.commit(); //end of the transaction scope: a is persisted at this point
            




            • 3. Re: UserTransactions and merge
              klaus_erber

              ok, thank you.

              The transaction boundry was ok in my original code, but the first tip was the right one.

              But there is another question. What about relationships like this:

              UserTransaction ut = sessionContext.getUserTransaction();
              ut.begin();
              MyEntity a = em.find(MyEntity.class, Long.valueOf(1));
              ut.commit();
              
              ut = sessionContext.getUserTransaction();
              ut.begin();
              a.setName("FOO2");
              MyRelatedBean b = a.getMyRelatedBean();
              em.merge(a);
              ut.commit();
              


              Of course, that ends with a LazyInitializeException. But can I 'integrate' a bean in the transaction to use it as normal accessed (via find or Query) bean?

              Greetings
              Klaus

              • 4. Re: UserTransactions and merge
                hoeft

                I haven't tried it yet but here's my suggestion.
                This code should work:

                UserTransaction ut = sessionContext.getUserTransaction();
                ut.begin();
                MyEntity a = em.find(MyEntity.class, Long.valueOf(1)); // <-- a is bound. Not initialized lazy fields can be accessed
                a.setName("FOO2");
                MyRelatedBean b = a.getMyRelatedBean();
                em.merge(a);
                ut.commit();
                


                It think your code isn't working, because your entity is detached after the first commit. You must bind it (with the find method) bevor you can access its lazy loaded fields. Another possibilitie is to enforce, that the field is loaded before the entity is detached. There are two ways to do this:
                - access the lazy loaded field before detachment (see the code below)
                - use ejb-QL (fetch join)

                UserTransaction ut = sessionContext.getUserTransaction();
                ut.begin();
                MyEntity a = em.find(MyEntity.class, Long.valueOf(1));
                a.getMyRelatedBean(); //the lazy attribut is initialized. If it is a list: call size()
                ut.commit(); //a is being detached
                
                ut = sessionContext.getUserTransaction();
                ut.begin();
                a.setName("FOO2");
                MyRelatedBean b = a.getMyRelatedBean();
                em.merge(a);
                ut.commit();
                



                Best regards
                Meinert