Search code examples
javajakarta-eejpaopenjpa

What's wrong with my JPA DAO? It will persist but there's an error on merge


I'm using JPA and EJBs on WebSphere 7.

I have the following class:

@Entity
@Table(name="WIDGET")
public class Widget implements Serializable {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  private String name;
  private String details;
/* getters and setters */
}

I have a DAO like so:

@Stateless
public class WidgetDAO implements WidgetDAOLocal {
  @PersistenceUnit
  private EntityManagerFactory emf;
  private EntityManager em;

  public EntityManager getEntityManager() {
    if (emf == null) {
      throw new Exception();
    }
    return emf.createEntityManager;
  }

  public Widget getWidget(Long id) {
    Widget widget = null;
    EntityManager em = getEntityManager();
    try {
      widget = (Widget)em.find(Widget.class, widgetId);
    } finally {
      em.close();
    }
    return widget;
  }

  public Widget createWidget(Widget widget) {
    EntityManager em = getEntityManager();
    try {
      em.persist(widget);
      em.flush();
    } finally {
      em.close();
    }
    return widget;
  }

  public Widget updateWidget(Widget widget) {
    EntityManager em = getEntityManager();
    try {
      widget = getEntityManager().merge(widget);
      em.flush();
    } finally {
      em.close();
    }
    return widget;
  }

}

The create works fine and my widget appears in the database.

But when I try to do a merge, I get an error. The code to do the merge and the error I get follows:

public WidgetService {

  @EJB
  private WidgetDAO widgetDAO;

  public WidgetDAO getWidgetDAO() {
    return this.widgetDAO;
  }

  public Widget getWidget(Long id) {
     return this.getWidgetDAO().getWidget(id);
  }

  public void updateDetails(Long widgetId, String details) {
    Widget w = this.getWidget(widgetId);
    w.setDetails(details);
    this.widgetDAO.updateWidget(w);
  }

}

The error is:

Exception caught from before_completion synchronization operation: 
<openjpa-1.2.1-SNAPSHOT-r422266:686069 nonfatal user error> org.apache.openjpa.persistence.InvalidStateException:
The generated value processing detected an existing value assigned to this field: com.mydomain.domain.Widget.id.  
This existing value was either provided via an initializer or by calling the setter method.  
You either need to remove the @GeneratedValue annotation or modify the code to the initializer processing.

Any help on this is greatly appreciated!


Solution

  • Thanks for the help everybody, I figured it out, here's the cause of the problem and the solution that worked for me.

    In my DAO I was doing this:

    @Stateless 
    public class WidgetDAO implements WidgetDAOLocal {
       @PersistenceUnit
       private EntityManagerFactory emf;
       private EntityManager em;
    
      public EntityManager getEntityManager() {
         if (emf == null) {
           throw new Exception();
         }
         return emf.createEntityManager;
       } 
    

    Because the EntityManagerFactory was being injected via the @PersistenceUnit annotation, the entities were "Application-Managed", causing some kind of conflict with WebSphere.

    I changed the code to this:

    @Stateless 
    public class WidgetDAO implements WidgetDAOLocal {
      @PersistenceContext 
      private EntityManager em;
    
      public EntityManager getEntityManager() {
        return em;
      } 
    
      public Widget updateWidget(Widget widget) throws Exception {
        return getEntityManager().merge(widget);
      }
    

    The @PersistenceContext annotation causes the entities to be "Container-Managed", and everything works now.

    Thanks for the all the help and suggestions here. At the end of the day, I worked out the solution after re-focusing on the "Managing Entities" section of the documentation here:

    http://docs.oracle.com/javaee/5/tutorial/doc/