10 Replies Latest reply on May 6, 2009 8:10 AM by asiandub

    Can't get my objects updated

    germandev.net-seam.wje-online.de

      Hi!


      I want to create simple CRUD functionality for an Entity Bean. So I created a manager - SFSB that should do that. Everything works fine besides the fact, that I can't update my entity.


      This is how that manager looks like:


      @Stateful
      @Name("kundenManager")
      @Scope(ScopeType.CONVERSATION)
      public class KundenManagerBean implements KundenManager
      {
          @Logger private Log log;
      
          private String strPasswortWiederholung = "";
      
          @DataModel("kunden")
          private List<Kunde> lstKunden;
      
          @DataModelSelection
          private Kunde objGewaehlterKunde = new Kunde();
      
          public void loescheKunden()
          {
               objGewaehlterKunde = em.merge(objGewaehlterKunde);
               setObjGewaehlterKunde(em.merge(objGewaehlterKunde));
               lstKunden.remove(objGewaehlterKunde);
               em.remove(objGewaehlterKunde);
          }
      
          @SuppressWarnings("unchecked")
           @Factory("kunden")
          public void findeKunden()
          {
               lstKunden = (List<Kunde>)em.createQuery("select k from Kunde k").getResultList();
          }
      
          @PersistenceContext(type = PersistenceContextType.EXTENDED)
          EntityManager em;
      
      
          public void neuenKundenErstellen()
          {
               try{
                    //TODO validation
                    em.persist(objGewaehlterKunde);
                    objGewaehlterKunde = new Kunde();
      
              log.info("Neuer Kunde angelegt");
               }catch(Exception ex)
               {
                    log.info(String.format("Exception: %s%nCause:%s%n", ex.getMessage(),ex.getCause()));
                    ex.printStackTrace();
               }
          }
      
          @Remove @Destroy
          public void remove(){}
      
           public void setStrPasswortWiederholung(String strPasswortWiederholung) {
                this.strPasswortWiederholung = strPasswortWiederholung;
           }
      
           public String getStrPasswortWiederholung() {
                return strPasswortWiederholung;
           }
      
           private void redirect()
           {
                org.jboss.seam.faces.Redirect objRedirect = new org.jboss.seam.faces.Redirect();
                objRedirect.setViewId("/kundenListe.xhtml");
                objRedirect.execute();
           }
      
      
           public Kunde getObjGewaehlterKunde() {
                return objGewaehlterKunde;
           }
      
           public void setObjGewaehlterKunde(Kunde objGewaehlterKunde) {
                this.objGewaehlterKunde = objGewaehlterKunde;
           }
      
           public void kundeEditieren() {
                //what to do here?
                em.flush();
                objGewaehlterKunde = new Kunde();
                redirect();
           }
      }
      





      When I am going to edit a 'Kunde', the related object is stored inside the 'objGewaehlterKunde ' variable. Then, on the edit page, I access the fields of the object Kunde by #{kundenManager.objGewaehlterKunde.fieldname. The field values are loaded correctly. But when I try to edit a value and click on the button, that triggers the  kundeEditieren() method nothing is saved. When looking at the output SQL on the console no Update Statement is triggered. The object seems to be empty at that position anyhow.


      I looked through many examples, but don't find a way to realize the update. Where is my mistake?


      Thank you in advance!

        • 1. Re: Can't get my objects updated
          gonorrhea

          1) In your kundeEditieren() method, you are executing a manual flush of persitence context.  But you have not specified MANUAL flush to begin with in your @Begin. 


          2) You don't have a @Begin (required for LRC).


          3) You don't have a @End (required for LRC).


          4) You should use @In to inject SMPC instead of @PersistenceContext (this is very important, so read up on this)



          So you have a CONVERSATION-scoped SFSB as your backing bean.  Good.


          You need to start a LRC and end the LRC with @Begin and @End.


          Use this for MANUAL flushing (if Hibernate is your persistence provider!):


          @Begin(join=true, flushMode=FlushModeType.MANUAL)



          Annotate your submit() or equivalent method with @End to demote the LRC to temporary conversation.

          • 2. Re: Can't get my objects updated
            asiandub

            to add the obvious:


            you don't need neither FlushMode.MANUAL nor seam-managed-persistence-context. but of course you are free to use it...


            a more conservativ JEE-approach would be to use FlushMode.COMMIT or FlushMode.AUTO and to let the persistence context be controlled by the JEE-container.


            cheers,
            jan

            • 3. Re: Can't get my objects updated
              germandev.net-seam.wje-online.de

              Jan Groth wrote on May 05, 2009 09:22:


              a more conservativ JEE-approach would be to use FlushMode.COMMIT or FlushMode.AUTO and to let the persistence context be controlled by the JEE-container.


              Thank you for this information - I think about using it there to save the 'em.flush' there when it works.



              Arbi Sookazian wrote on May 05, 2009 00:56:


              1) In your kundeEditieren() method, you are executing a manual flush of persitence context.  But you have not specified MANUAL flush to begin with in your @Begin. 

              2) You don't have a @Begin (required for LRC).

              3) You don't have a @End (required for LRC).

              4) You should use @In to inject SMPC instead of @PersistenceContext (this is very important, so read up on this)


              I did 1) to 3) but couldn't replace the @PersistenceContext because of the following error message: '@In attribute requires non-null value: kundenManager.em'


              this is how the modified class looks:


              @Stateful
              @Name("kundenManager")
              @Scope(ScopeType.CONVERSATION)
              public class KundenManagerBean implements KundenManager
              {
                  @Logger private Log log;
              
                  private String strPasswortWiederholung = "";
              
                  @DataModel(value = "kunden", scope = ScopeType.PAGE)
                  private List<Kunde> lstKunden;
              
                  private Kunde objGewaehlterKunde = new Kunde();
              
                  public void loescheKunden(Kunde objKunde)
                  {
                       objKunde = em.merge(objKunde);
                       lstKunden.remove(objKunde);
                       em.remove(objKunde);
                  }
              
                  @SuppressWarnings("unchecked")
                   @Factory("kunden")
                  public void findeKunden()
                  {
                       lstKunden = (List<Kunde>)em.createQuery("select k from Kunde k").getResultList();
                  }
              
                  @PersistenceContext(type = PersistenceContextType.EXTENDED)
                  //@In
                  EntityManager em;
              
              
                  public void neuenKundenErstellen()
                  {
                       try{
                            //TODO validation
                            log.info("Neuer Firma: " + objGewaehlterKunde.getStrFirma());
                            em.persist(objGewaehlterKunde);
                            objGewaehlterKunde = new Kunde();
              
                      log.info("Neuer Kunde angelegt");
                       }catch(Exception ex)
                       {
                            log.info(String.format("Exception: %s%nCause:%s%n", ex.getMessage(),ex.getCause()));
                            ex.printStackTrace();
                       }
                  }
              
                  @Remove @Destroy
                  public void remove(){}
              
                   public void setStrPasswortWiederholung(String strPasswortWiederholung) {
                        this.strPasswortWiederholung = strPasswortWiederholung;
                   }
              
                   public String getStrPasswortWiederholung() {
                        return strPasswortWiederholung;
                   }
              
                   private void redirect()
                   {
                        org.jboss.seam.faces.Redirect objRedirect = new org.jboss.seam.faces.Redirect();
                        objRedirect.setViewId("/kundenListe.xhtml");
                        objRedirect.execute();
                   }
              
              
                   public Kunde getObjGewaehlterKunde() {
                        if (objGewaehlterKunde == null)
                             objGewaehlterKunde = new Kunde();
                        return objGewaehlterKunde;
                   }
              
                   public void setObjGewaehlterKunde(Kunde objGewaehlterKunde) {
                        this.objGewaehlterKunde = objGewaehlterKunde;
                        log.info("Firma: " + objGewaehlterKunde.getStrFirma());
                   }
              
                   @End
                   public void kundeEditieren() {
                        log.info("Edited Firma: " + objGewaehlterKunde.getStrFirma());
                        em.flush();
                        objGewaehlterKunde = new Kunde();
                        redirect();
                   }
                   @Begin(flushMode = FlushModeType.MANUAL, join = true)
                   public String waehleKunde(Kunde objKunde) {
                        this.objGewaehlterKunde = em.merge(objKunde);
                        log.info("Gewaehlter Kunde: " + objGewaehlterKunde.getStrLogin());
                        log.info("Editseite!");
                        return "edit";
                   }
              }




              again I can trouble-free add new 'Kunde' - objects but still can't edit them.
              The object is assigned with the method 'public String waehleKunde(Kunde objKunde)' on the overview page. then the user is redirected (using 'from-outcome="edit"') to the edit page. The values are assigned using

              #{kundenManager.objGewaehlterKunde.propertyname}

              and loaded correctly. The edit button calls the 'kundeEditieren()', but when the method is called the old values are used. I tried to put a debug output to the setter of the object - and it isn't called there.


              Do you know where the remaining error might be?


              Thank you so much in advance for your help!

              • 4. Re: Can't get my objects updated
                gonorrhea

                Jan Groth wrote on May 05, 2009 09:22:


                to add the obvious:

                you don't need neither FlushMode.MANUAL nor seam-managed-persistence-context. but of course you are free to use it...

                a more conservativ JEE-approach would be to use FlushMode.COMMIT or FlushMode.AUTO and to let the persistence context be controlled by the JEE-container.

                cheers,
                jan


                If you need to achieve atomic conversations (i.e. for multiple request/response HTTP cycles, only commit entity changes when the conversation completes), then you must use SMPC with Hibernate MANUAL flush.  This is one of the major features of Seam's transaction handling and is highly recommended to use for a variety of reasons (see the various Seam books for details).


                One reason to not use MANUAL flush is b/c it is if you end up swapping out Hibernate for Toplink, etc. then you will need to refactor, as this manual flush feature is a Hibernate-specific extension.

                • 5. Re: Can't get my objects updated
                  gonorrhea


                  I did 1) to 3) but couldn't replace the @PersistenceContext because of the following error message: '@In attribute requires non-null value: kundenManager.em'

                  This usually indicates that auto-create="true" is not set in your components.xml for SMPC.


                  Try this:


                  <persistence:managed-persistence-context name="entityManager"
                                                       auto-create="true"
                                        persistence-unit-jndi-name="java:/fooEntityManagerFactory"/> 



                  If you don't add the auto-create="true", then you must do @In(create=true) for the EntityManager injection in every Seam component which needs that injection (which is more work!)


                  Remember that when you inject the entityManager instance in a Seam component, it must match what you have above.


                  So for the above config, this will not work:


                  @In EntityManager em;



                  this will work:


                  @In EntityManager entityManager;



                  NOTE: make sure that java:/fooEntityManagerFactory exists in your persistence.xml!


                  example:

                  <property name="jboss.entity.manager.factory.jndi.name" value="java:/fooEntityManagerFactory"/>

                  • 6. Re: Can't get my objects updated
                    asiandub

                    Arbi Sookazian wrote on May 05, 2009 17:38:



                    Jan Groth wrote on May 05, 2009 09:22:


                    to add the obvious:

                    you don't need neither FlushMode.MANUAL nor seam-managed-persistence-context. but of course you are free to use it...

                    a more conservativ JEE-approach would be to use FlushMode.COMMIT or FlushMode.AUTO and to let the persistence context be controlled by the JEE-container.

                    cheers,
                    jan


                    If you need to achieve atomic conversations (i.e. for multiple request/response HTTP cycles, only commit entity changes when the conversation completes), then you must use SMPC with Hibernate MANUAL flush.  This is one of the major features of Seam's transaction handling and is highly recommended to use for a variety of reasons (see the various Seam books for details).

                    One reason to not use MANUAL flush is b/c it is if you end up swapping out Hibernate for Toplink, etc. then you will need to refactor, as this manual flush feature is a Hibernate-specific extension.


                    no doubt about that, but it simply doesn't seem to me that Peter is trying to achieve atomic conversations :-)


                    • 7. Re: Can't get my objects updated
                      gonorrhea

                      You may be correct but I was told by PMuir a while back to always use @In to inject SMPC rather than @PersistenceContext.


                      But that's up to Peter and his particular use case I guess.

                      • 8. Re: Can't get my objects updated
                        germandev.net-seam.wje-online.de

                        Thank you for all these answers - this load of information really helped me on! I am going to rewrite my application and reconsider my design.


                        It's really great that even greenhorns like me are helped in this community!


                        The only thing I don't understand at all:


                        Why does it make a difference how the EntityManager is called when it's going to be injected?

                        • 9. Re: Can't get my objects updated
                          gonorrhea

                          peter irmstadt wrote on May 05, 2009 22:39:


                          Why does it make a difference how the EntityManager is called when it's going to be injected?


                          refer to this API doc: http://docs.jboss.org/seam/2.1.1.GA/api/org/jboss/seam/persistence/ManagedPersistenceContext.html


                          This is the class that is used by this config in components.xml:


                          <persistence:managed-persistence-context name="entityManager"
                                                               auto-create="true"
                                                persistence-unit-jndi-name="java:/fooEntityManagerFactory"/>



                          The package is org.jboss.seam.persistence.  The class is ManagedPersistenceContext.  And the attributes typically map to setter methods on the class (however, in the API doc I'm not seeing a setName or setAutoCreate which is strange). 


                          Anyways, each SMPC is CONVERSATION-scoped as per:


                          @Scope(value=CONVERSATION)
                          @BypassInterceptors
                          @Install(value=false)
                          public class ManagedPersistenceContext



                          So in this case the instance name of SMPC is registered in the CONVERSATION scope as entityManager.  If you try injecting SMPC as follows: @In EntityManager em;, it won't work.


                          Hope that helps.  And if I'm wrong on some of the details, somebody correct me!

                          • 10. Re: Can't get my objects updated
                            asiandub

                            to put Arbi's answer in simple words:



                             @In EntityManager em;
                            
                             @In EntityManager entityManager;




                            The difference between the two lines of code are that they are both defaulting against different component names. The first variant searches for a component named em, the second for a component named entityManager. This is part of the convention over configuration paradigma and certainly no magic at all :-)


                            To stick with your field named em just use this:


                              @In(value="entityManager")
                              EntityManager em;




                            and everything's will work like a charme... :-)


                            Cheers,
                            Jan