11 Replies Latest reply on Nov 20, 2009 8:56 PM by asookazian

    Starting new conversation resets flush mode to auto

    pmurphy.pjmurphy.paddypower.com

      I've noticed that starting a new conversation via the @Begin annotation resets the flush mode for all entity managers to auto (as this is the default flush mode if none is specified). This is a bit annoying as I have two entity managers (seam injected) where one is set to auto flush and the other is set to manual flush. However, anytime a conversation is started both entity managers are reset to auto (or manual if that was the specified flush mode).


      To over come this problem for the moment I am calling a method that resets the flush mode.



      public void resetFlushModes() {
       ((Session)getEntityManager().getDelegate()).setFlushMode(FlushMode.AUTO);
      ((Session)getManualEntityManager().getDelegate()).setFlushMode(FlushMode.MANUAL);          
      }
      



      My solution seems to be a bit cumbersome, so would anyone have any better ideas on how to manage this?


      Thanks,


      Philip


        • 1. Re: Starting new conversation resets flush mode to auto
          pmurphy.pjmurphy.paddypower.com

          Actually, even my resetFlushModes() method does not seem to work. If you set one entity manager then the other entity manager is also set. I've even created a new persistence-unit, so that I could have one for the entity manager that I want to keep from auto-flushing and one that auto-flushes. However, whenever I change the flush mode of one entity manager the other entity manager's flush mode is also set. It appears that it is impossible to have two separate entity managers in Seam/Hibernate with different flush modes at the same time. Does anyone have an opinion on this?

          • 2. Re: Starting new conversation resets flush mode to auto
            pmurphy.pjmurphy.paddypower.com

            Looking at the org.jboss.seam.persistence.PersistenceContexts (a singleton class per conversation - PersistenceContexts.instance()) code when the entity manager is being initialized via the ManagedPersistenceContext


            
            org.jboss.seam.persistence.ManagedPersistenceContext.initEntityManager()  
            
              private void initEntityManager()
               {
                  entityManager = getEntityManagerFactoryFromJndiOrValueBinding().createEntityManager();
                  PersistenceProvider persistenceProvider = PersistenceProvider.instance();
                  entityManager = persistenceProvider.proxyEntityManager(entityManager);
                  setEntityManagerFlushMode( PersistenceContexts.instance().getFlushMode() );
            ...
            }
            
            
            



            it would appear that only one persistent context per conversation is supported in Seam.

            • 3. Re: Starting new conversation resets flush mode to auto
              pmurphy.pjmurphy.paddypower.com

              If someone else has the same problem, a possible work around is to look up second entity manager and not let Seam inject it.


              private EntityManager manualEntityManager;
              
              @Create
              @Override
              public void create() {
                  manualEntityManager = (EntityManager)Component.getInstance("manualEntityManager");
                  ((Session)manualEntityManager.getDelegate()).setFlushMode(FlushMode.MANUAL);
              }
              


              • 4. Re: Starting new conversation resets flush mode to auto
                asookazian

                your scenario is interesting but why do you need one AUTO and one MANUAL?

                • 5. Re: Starting new conversation resets flush mode to auto
                  pmurphy.pjmurphy.paddypower.com

                  I have a complex screen using different modules (included xhtml files) where part of it uses fast update (i.e. when the user enters data it is automatically pushed to the server using ajax on validation), and another part of the screen where values need to be validated (via ajax request) but not saved to the database until the user presses a save button. To handle the latter case, I do a look up using the standard entity manager, whose flush mode is auto, and set the individual changes from the entity that was looked up using the manual entity manager and push them to the standard one. At this point the individual changes are saved to the database as the flush mode is auto for the standard entity manager.


                  So, in short, I have a requirement for some changes to be auto-saved and some changes that mustn't be saved until a save button is pressed.


                  BTW, for the previous snippet of code to work you would also need to define the following in your components.xml file.


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

                  • 6. Re: Starting new conversation resets flush mode to auto
                    pmurphy.pjmurphy.paddypower.com

                    Slight correction to components.xml as you can shared the same persistent unit.


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



                    Of course, the JNDI name 'java:/myEntityManagerFactory' needs to correspond to the 'jboss.entity.manager.factory.jndi.name' property defined in your persistence-dev.xml and persistence-prod.xml files.


                    • 7. Re: Starting new conversation resets flush mode to auto
                      asookazian

                      To handle the latter case, I do a look up using the standard entity manager, whose flush mode is auto, and set the individual changes from the entity that was looked up using the manual entity manager and push them to the standard one. At this point the individual changes are saved to the database as the flush mode is auto for the standard entity manager.

                      I don't see why you can't use either one EntityManager with manual flush or two EntityManagers with manual flush.  The latter case is typically required when you need to do CRUD on more than one DB (which is likely not the case here).


                      With Seam apps it is typically recommended to use SMPC with Hibernate manual flush (if Hibernate is your persistence provider).  The advantage is that you can keep the persistence context open for the duration of the conversation and thus the entities don't get detached until after the em.flush() to the SMPC (which typically occurs at the end of the conversation).


                      So the main point here is that irrespective of the fast AJAX save and regular HTTP POST of form save, you should be able to flush() the SMPC twice per conversation (or n times prior to the end of the conversation).


                      Here's an example using SFSB:


                      @Name("foo")
                      @Stateful
                      public class Foo {
                      
                          @In  //use SMPC, not container-managed PC
                          private EntityManager entityManager;
                      
                          @Begin(join=true, flushMode=FlushModeType.MANUAL)
                          public void someStartMethod() {
                              //do some stuff or start LRC from pages.xml
                          }
                      
                          public void fastUpdate() {
                              //do some stuff; remember merge() is a crude operation and is not required
                              //b/c JPA does write-behind and dirty-tracking of changes in the PC
                              //via the 1st level cache
                              entityManager.flush();
                          }
                      
                          @End
                          public void save() {
                              //do some stuff like entityManager.persist(foo) or update, etc.
                              entityManager.flush();
                          }
                      
                      }



                      The SMPC is conversation-scoped, so it remains open until the end of the LRC (thus avoiding LIEs).  In Seam apps, if you are using Hibernate, you should typically never need to use AUTO or COMMIT modes for flushing the PC.

                      • 8. Re: Starting new conversation resets flush mode to auto
                        pmurphy.pjmurphy.paddypower.com

                        Hi Arbi,


                        Thanks for the response. The reason I can't use just one entity manager is because of the screen layout and business requirement. Let me explain. I have a screen (web page) where the data that is represented on the screen is from multiple entities. The screen is spit up into different parts where the user needs the ability to update different entities independently of each other. When they change some parts of the screen the changes need to be auto saved while others parts need to be delayed-saved until the user presses a save button. There are multiple save buttons on the screen to update different parts of it where one save affects some set of entities but not other entities on separate parts of the same screen.


                        I am trying to achieve very fine-grained control of what is saved and when it is saved on a very complex control screen.


                        If I used your approach when I called entityManager.flush() it would flush all changes on the screen and not just the particular ones that the user was working with. That is, the user has modified two or more parts of data on the screen, but only wants to save one part as he still hasn't made up his mind if he wants to commit the other changes that they have made.


                        Thanks again for your input.


                        Philip

                        • 10. Re: Starting new conversation resets flush mode to auto
                          pmurphy.pjmurphy.paddypower.com

                          Hi Arbi,


                          Thanks for the links - interesting reading.


                          The posts cover using two manual entity managers which have both their flush modes set to manual. In my specific case, I need to use one entity manager with flush mode auto and one manual to control different parts of a complex screen(s). The auto one is required as certain parts of the screen (which are very complex) have been developed separately by other developers which have used auto flush mode (actually most screens in the application use auto flushing). My particular part of the main control screen, which again is a very complex component needs deferred-save functionality, so in this case I use an entity manager with flush mode set to manual. As the project has been in development for 6 months I can't get or have the time to change all entity managers to manual flushing and use flush-on-demand. I guess we are where we are, but at least I have a solution that meets the business requirements, but without the need to change how different components work currently.



                          All the same, thanks for the ideas.


                          Cheers,


                          Philip

                          • 11. Re: Starting new conversation resets flush mode to auto
                            asookazian

                            Ok, so the problem is you must use one AUTO flush and one MANUAL flush...


                            this is your solution, correct?:


                            private EntityManager manualEntityManager;
                            
                            @Create
                            @Override
                            public void create() {
                                manualEntityManager = (EntityManager)Component.getInstance("manualEntityManager");
                                ((Session)manualEntityManager.getDelegate()).setFlushMode(FlushMode.MANUAL);
                            }



                            Why don't you use @Unwrap like is done in this example:


                            @Name("entityManager")
                            @Scope(ScopeType.CONVERSATION)
                            public class DynamicEntityManager {
                            
                                 @Unwrap
                                 public EntityManager getEntityManager() {
                                      EntityManager entityManager = (EntityManager)Component.getInstance("entityManager");
                                      return entityManager;
                                 }
                            }



                            That way you can simply reference entityManager and you'll get the instance you want.  No need for @Create method in every class that needs the EM...


                            In any event, this sounds like a possible JIRA issue.  not sure what the official recommendation is for this scenario...