3 Replies Latest reply on Sep 18, 2007 3:42 PM by tim_ph

    Creating and Updating records in single operation: sensible

    markwhiting

      Hi

      I'm interested to hear people's opinions on the way I've implemented a solution. I'd like to know if there's a cleaner or simpler pattern...



      Requirement:

      When a user clicks an 'update' button, create a new record in a table and also update an existing record in the same table. The UI page uses <h:inputText/> fields. Application flow:

      1. User selects an existing record from a CRUD page and is presented with an edit page for a that record
      2. User edits some fields of that record and clicks 'update'
      3. A new record must be created, which is a copy of the existing record but with any fields the user changed in step 2 upated with those changes
      4. Some non-UI fields of the existing record must be changed and the record then updated in the table (this record must otherwise remain unchanged)



      A solution:

      Relevant code (abridged for brevity):


      i. Edit page extract:

      note: This page is rendered after the user selects a record from a different CRUD page.

      <h:form>
      
       <s:decorate id="decoration" template="edit.xhtml">
       <h:inputText id="one"
       value="#{myEntityHome.instance.UIProperty}" >
       <a:support event="onblur" reRender="decoration"
       bypassUpdates="true" ajaxSingle="true" />
       </h:inputText>
       </s:decorate>
      
       <h:commandButton id="update" value="Update" action="#{myEntityHome.update}" />
      
      </h:form>




      ii. Extended Home component:

      note:

      a. find() is invoked in step 1 (when the user selects a record on the CRUD page).

      b. update() is invoked in step 2 (when the user clicks the update button).

      c. Assume MyEntity is a simple EJB Entity with properties corresponding to those referenced below.


      @Name("myEntityHome")
      public class MyEntityHome extends EntityHome<MyEntity>
      
       private MyEntity existingEntity;
       private List<AssociatedEntityList> associatedEntityLists = new ArrayList<AssociatedEntityList>();
      
       @In(create = true)
       EntityManager em;
      
       public List<AssociatedEntityList> getAssociatedEntityLists() {
       return associatedEntityLists;
       }
      
       @Override
       public MyEntity find() {
      
       // Store the contents of the existing entity
       MyEntity myEntity = super.find();
       existingEntity = new MyEntity(myEntity.getId(),
       myEntity.getUIProperty(),
       myEntity.getNonUIProperty(),
       myEntity.getAssociatedEntityLists());
       return myEntity;
       }
      
      
       @Begin(join = true, flushMode = FlushModeType.MANUAL)
       @Override
       @Transactional
       public String update() {
      
       // For step 3
       MyEntity myEntity = createNewEntity();
      
       // For step 4: Refresh the existing entity as the user may have changed
       // some UI fields, which must not be updated in the db
       em.refresh(getInstance());
      
       // For step 4
       getInstance().setNonUIProperty("changed");
      
       entityManager.flush();
       Contexts.removeFromAllContexts("myEntityHome");
       return "createdAndUpdated";
       }
      
      
       private MyEntity createNewEntity() {
      
       MyEntity myEntity = new MyEntity();
      
       // Copy contents of current UI fields into the newly created entity
       myEntity.setUIPropertyOne(getInstance().getUIPropertyOne());
      
       // Copy contents of non-UI fields into the newly created entity
       myEntity.setNonUIPropertyOne(getInstance().getNonUIPropertyOne());
      
       // Copy associated entities into the newly created entity
       for (AssociatedEntityList ael : associatedEntityLists)
       ael.setMyEntity(myEntity);
       myEntity.setAssociatedEntityLists(associatedEntityLists);
      
       return myEntity;
       }


      As you can see, I'm using EntityManager refreshing and manual flushing and am having to make a 'clone' (which could be done by implementing Cloneable instead) of the existing entity in createNewEntity().


      Any feedback appreciated...


      Thanks