3 Replies Latest reply on Jun 27, 2008 2:40 AM by Jacob Orshalick

    Begin(nested=true,flushMode=MANUAL) persists without flush()

    Jake C Newbie

      I am starting a nested conversation with flushMode=MANUAL and editing within a modalPanel. When someone enters invalid information, I keep the modalPanel up and attempt to show an error message (error messages not working, posted in another thread), and do NOT flush() to the DB. However, my dataDetails div is still reRendered under the modalPanel (expected), and shows that the info is changed anyway (unexpected). If I then abandon the changes, the bad data is still in the DB.


      Isn't flushMode=MANUAL supposed to prevent anything getting flushed to the DB? How do I get this to work correctly?


      main.xhtml



      <ui:composition xmlns=...>
        <ui:define name="body">
          <a:include viewId="modal.txml"/>
          ....
          <h:form id="infoForm">
            <a:commandLink id="editInfo" value="Edit Info" action="#{myBean.editInfo(currentInfo)}"
                           oncomplete="Richfaces.showModalPanel('modalPanel');" reRender="modalPanelDiv"/>
          </h:form>
        </ui:define>
      </ui:composition>
      



      modal.txml


      <ui:composition xmlns=...>
        <rich:modalPanel id="modalPanel" autosized="true" zindex="2000">
          <h:form id="editForm">
            <s:validateAll>
              <s:div id="modalPanelDiv">
                <s:decorate id="nameDecor" template="edit.txml">
                  <ui:define name="label">Name:</ui:define>
                  <h:inputText id="name" value="#{myBean.name}"/>
                </s:decorate>
                <a:commandButton id="abandon" image="/img/button/abandon.gif"  action="#{myBean.abandonEdits}" title="Abandon Changes"
                                 oncomplete="if(#{myBean.closingModalWindow}) Richfaces.hideModalPanel('modalPanel'); return false;"/>
                <a:commandButton id="submit" image="/img/button/done.gif" action="#{myBean.commitEdits}" title="Commit Changes"
                                 oncomplete="if(#{myBean.closingModalWindow}) Richfaces.hideModalPanel('modalPanel'); return false;"
                                 reRender="dataTable,dataDetails"/>
              </s:div>
            </s:validateAll>
          </h:form>
        </rich:modalPanel>
      </ui:composition>
      



      MyBeanBean.java


      ...
      @Begin(nested = true, flushMode = FlushModeType.MANUAL)
      public void editInfo(Info i) {
        info = entityManager.merge(i);
        editingInfo = true;
        closingModalWindow = false;
      }
      
      public void commitEdits() {
        closingModalWindow = true;
        if(// Detect invalid entry//) {
          facesMessages.addToControlFromResourceBundle("name", "nameValidationError");
          closingModalWindow = false;
          return;
        }
      
        if (!entityManager.contains(info))
          entityManager.persist(info);
      
        entityManager.flush();
        info = entityManager.find(Info.class, info.getId());
        closingModalWindow = true;
        Conversation.instance().endBeforeRedirect();
      }
      
      public void abandonEdits() {
        if (entityManager.contains(info))
          {
          entityManager.refresh(info);
          info = entityManager.find(Info.class, info.getId());
          }
      
        closingModalWindow = true;
        Conversation.instance().endBeforeRedirect();
        return;
      }
      ...
      


        • 1. Re: Begin(nested=true,flushMode=MANUAL) persists without flush()
          Jacob Orshalick Apprentice

          When you begin the parent conversation are you setting flushMode to MANUAL?  Be aware that the PersistenceContext is shared between parent and nested conversations.

          • 2. Re: Begin(nested=true,flushMode=MANUAL) persists without flush()
            Jake C Newbie

            Jacob Orshalick wrote on Jun 26, 2008 21:25:


            When you begin the parent conversation are you setting flushMode to MANUAL?

            No, the parent Conversation is not MANUAL.



            Jacob Orshalick wrote on Jun 26, 2008 21:25:


            Be aware that the PersistenceContext is shared between parent and nested conversations.

            I'm not sure I understand what you are getting at. Does that mean that flushMode is ignored when nested=true, and it always inherits the flushMode of the parent Conversation?


            I suspect what you are getting at is that a flush on either the parent or other nested Conversation will also flush all other changes in any other parent/nested Conversations, but I am not currently doing that.


            Currently, my parent thread is not actually editing anything, just displaying, and there is no manual flushing at all. Nothing is calling flush() in either the parent Conversation or any child Conversations, so why are the changes being persisted?


            Eventually, I WILL be doing this same thing from a parent thread that will be editing, and should not be persisted when the nested Conversation calls flush(). Is there a solution to having a flush in the nested Conversation persist the parent data? I see that using @PerNestedConversation on a FIELD item (like an EntityManager) is still not valid.

            • 3. Re: Begin(nested=true,flushMode=MANUAL) persists without flush()
              Jacob Orshalick Apprentice

              I'm not sure I understand what you are getting at. Does that mean that flushMode is ignored when nested=true, and it always inherits the flushMode of the parent Conversation?

              No, the ConversationInterceptor actually does change the flushMode even when a nested conversation is encountered (although there is currently a TODO about what to do when nested conversations are encountered).



              I suspect what you are getting at is that a flush on either the parent or other nested Conversation will also flush all other changes in any other parent/nested Conversations, but I am not currently doing that.

              Yes.



              Nothing is calling flush() in either the parent Conversation or any child Conversations, so why are the changes being persisted?

              That's surprising.  As mentioned above the underlying Hibernate Session is switched to MANUAL flushMode when the nested conversation is encountered.  I'm curious though as I have never tried changing the flushMode in the nested conversation.  Try moving the flushMode setting to the @Begin of the root conversation.  If you still have the same issue we know it is an issue in your code and can look a bit deeper.



              Is there a solution to having a flush in the nested Conversation persist the parent data?

              See:  JBSEAM-2121.   The only other options at the moment are to make it a separate conversation or retrieve a new EntityManager instance and merge the entity you wish to edit.