title: RCP Editor and JPA merge
body: <p>I am updating an RCP based application to use JPA 2.1 (EclipseLink's implementation) from Hibernate 3.x.  The JPA merge behavior is causing me problems.  The issue I am seeing is when I assign the returned value to the model object in the RCP editor (inherited from FormEditor) it is a new entity and changes are not being persisted on subsequent saves.  </p>
  
  <p>I'm seeking input on how best to update the RCP Editor model with the new object returned from JPA.merge().</p>
  
  <p>Note: I understand the difference between hibernate's saveOrUpdate and JPA's persist.  </p>
  
  <p>The two approaches that I see are:</p>
  
  <ol>
  <li>In my service layer do a deep copy from the new entity returned from JPA.merge() into the entity that was passed into the service.save() method and do not make the assignment in the editor.doSave() method.</li>
  <li>Associate the model in the RCP editor to the new entity returned from JPA.merge()</li>
  </ol>
  
  <p>The object graph is fairly complex and deep so writing a deep copy is not trivial.  However, I don't know how to approach #2 above.</p>
  
  <p>I'm open to any ideas on how to approach #1 / #2 or if there are options #3 - #n that I am missing.</p>
  
  <p>Thanks for taking time to read my question!</p>
  
  <p>Here is my current Editor.doSave method</p>
  
  <pre><code>@Override
  public void doSave(IProgressMonitor monitor) {
      this.overviewPage.getDataBindingContext().updateModels();
      this.getActivePageInstance().getManagedForm().commit(true);
      try {
          motor = Activator.getAcMotorEntity().save(motor);
      } catch (BusinessException e) {
          StatusManager.getManager().handle(
                  new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Unable to save the motor to the database", e),
                  StatusManager.LOG | StatusManager.SHOW);
      }
      if (motor.getId() == 1L) {
          this.setPartName("[DEFAULT VALUES]");
      } else {
          this.setPartName(this.motor.getJobNumber());
      }
      this.setDirty(false);
  }
  </code></pre>
  
  <p>and my service.save() which calls JPA's merge</p>
  
  <pre><code>@Override
  public IT save(IT entity) throws BusinessException {
      EntityManager em = factory.createEntityManager();
      IT savedEntity = null;
  
      getLogger().debug("Save {} with id of {} ", entity.getClass().getName(), ((IDatabaseEntity) entity).getId());
      try {
          em.getTransaction().begin();
          savedEntity = em.merge(entity); // re-attach
          em.getTransaction().commit();
          this.firePropertyChange(entity, savedEntity);
      } catch (OptimisticLockException ole) {
          getLogger().error("Load " + entity.getClass().getName() + " with id of " + ((IDatabaseEntity) entity).getId(), ole);
          throw JpaExceptionFactory.createRecordChanged(ole, entity == null ? 0 : ((IDatabaseEntity) entity).getId(),
                  entity == null ? "null entity" : entity.getClass().getName());
      } catch (PersistenceException pe) {
          getLogger().error("Load " + entity.getClass().getName() + " with id of " + ((IDatabaseEntity) entity).getId(), pe);
          if (em.getTransaction().isActive()) {
              em.getTransaction().rollback();
          }
          throw JpaExceptionFactory.createPersistence(pe, entity == null ? 0 : ((IDatabaseEntity) entity).getId(),
                  entity == null ? "null entity" : entity.getClass().getName());
      } catch (Throwable t) {
          getLogger().error("Load " + entity.getClass().getName() + " with id of " + ((IDatabaseEntity) entity).getId(), t);
          if (em.getTransaction().isActive()) {
              em.getTransaction().rollback();
          }
          throw JpaExceptionFactory.createUnknownDatabase(t, entity == null ? 0 : ((IDatabaseEntity) entity).getId(),
                  entity == null ? "null entity" : entity.getClass().getName());
      } finally {
          if (em != null &amp;&amp; em.isOpen()) {
              em.close();
          }
      }
  </code></pre>