2 Replies Latest reply on Apr 26, 2007 10:40 AM by Fernando Montaño

    Weird behavior editing Entity with @ManyToMany and Ajax4JSF

    Fernando Montaño Expert

      Hi Folks.

      After several days trying to found a reason to the problem I will describe here I gave up.

      Maybe someone here had a similar problem or can see WTF I'm doing wrong.

      I have a seam application and I'm using Ajax4JSF to perform some validations using a4j:support. I took as base the booking example of seam.

      The problem is when I try to edit a simple entity in a conversation, the entity is a User entity (username, firstname, lastname) and this entity has a @ManyToMany relationship with a Role entity, this relationship is displayed as checkboxes in the page and here I'm using s:convertEntity to make this work. All works fine without a4j:support in the input fields. But, when I add the a4j:support to some field, then the entity is persited in the database every time a a4j request is done (a4j:support onblur). This means every time I press the tab key in the form page I can see something like this in the server console:

      Hibernate: update users set password=?, firstname=?, lastname=?, email=?, version=?, country=?, city=?, province=?, street=
      ?, enabled=? where username=? and version=?
      Hibernate: update users set password=?, firstname=?, lastname=?, email=?, version=?, country=?, city=?, province=?, street=
      ?, enabled=? where username=? and version=?
      Hibernate: update users set password=?, firstname=?, lastname=?, email=?, version=?, country=?, city=?, province=?, street=
      ?, enabled=? where username=? and version=?
      Hibernate: update users set password=?, firstname=?, lastname=?, email=?, version=?, country=?, city=?, province=?, street=
      ?, enabled=? where username=? and version=?
      Hibernate: update users set password=?, firstname=?, lastname=?, email=?, version=?, country=?, city=?, province=?, street=
      ?, enabled=? where username=? and version=?
      Hibernate: update users set password=?, firstname=?, lastname=?, email=?, version=?, country=?, city=?, province=?, street=
      


      But, I did not press any button or submit the form, and even the action (seam component) is never called.


      Here is my code:

      User entity:
      
      @Entity
      @Table(name = "users")
      @Name("user")
      public class User implements Serializable {
      
       private static final long serialVersionUID = 1559233654671826129L;
      
       @Id
       @Column(name = "username")
       @Length(max = 50)
       @NotNull
       private String username;
      
       @Column(name = "password", nullable = false)
       @Length(min = 6, max = 200)
       @NotNull
       private String password;
      
      
       @Column(name = "firstname", nullable = false)
       @NotNull
       @Length(max = 80)
       private String firstName;
      
       @Column(name = "lastname", nullable = false)
       @NotNull
       @Length(max = 80)
       private String lastName;
      
      
      
       @Version
       @Column(name = "version")
       private long version;
      ...
      
      
       @ManyToMany(fetch = FetchType.LAZY)
       @JoinTable(
       name = "userrole",
       joinColumns = @JoinColumn(name = "username"),
       inverseJoinColumns = @JoinColumn(name = "name")
       )
       @OrderBy("name asc")
       private List<Role> roles;
      ....
      




      Edit xhtml page:
      
      <ui:define name="body">
       <h:form id="userForm">
       <h:commandButton action="#{userAction.update}" value="#{messages['Common.save']}"
       styleClass="button" />
      
      
      <a4j:commandButton action="#{userAction.cancel}" value="#{messages['Common.cancel']}"
       styleClass="button" immediate="true"/>
       </div>
      
       <rich:panel id="formPanel">
       <f:facet name="header">#{messages['User.edit']}</f:facet>
      
       <s:decorate id="usernameDecorate" template="/include/viewField.xhtml">
       <ui:define name="label">#{messages['User.username']}</ui:define>
       #{user.username}
       </s:decorate>
      
      
       <s:decorate id="firstNameDecorate" template="/include/inputField.xhtml">
       <ui:define name="label">#{messages['User.firstName']}</ui:define>
      
       <h:inputText id="firstName" value="#{user.firstName}" required="true"
       maxlength="80" tabindex="4" styleClass="input">
       <a4j:support event="onblur" reRender="firstNameDecorate"/>
       </h:inputText>
      
       </s:decorate>
      
      
       <s:decorate id="lastNameDecorate" template="/include/inputField.xhtml">
       <ui:define name="label">#{messages['User.lastName']}</ui:define>
      
       <h:inputText id="lastName" value="#{user.lastName}" required="true"
       maxlength="80" tabindex="5" styleClass="input">
       <a4j:support event="onblur" reRender="lastNameDecorate"/>
       </h:inputText>
      
       </s:decorate>
      
       //If I remove below field, all works fine
       <s:decorate template="/include/inputField.xhtml">
       <ui:define name="label">#{messages['User.assignRoles']}</ui:define>
       <h:selectManyCheckbox value="#{user.roles}" id="userRoles" tabindex="13" styleClass="checkBox">
       <s:selectItems value="#{roleList}" var="role" label="#{messages[role.description]}"/>
       <s:convertEntity/>
       </h:selectManyCheckbox>
       </s:decorate>
      
       </rich:panel>
      
      
       </h:form>
      
      
      


      User action component
      
      @Stateful
      @Name("userAction")
      @Scope(ScopeType.CONVERSATION)
      @Restrict("#{s:hasRole('admin')}")
      public class UserAction implements Serializable, IUserAction {
      
       private static final long serialVersionUID = -8072889837049283608L;
      
      
      
       @In
       private EntityManager entityManager;
      
       @In(required = false)
       @Out(required = false)
       private User user;
      
       @In
       private FacesMessages facesMessages;
      
      
      
       @Begin(ifOutcome = "userEdit")
       public String select(User selectedUser) {
       log.debug("selecting user");
       try {
      
       user = entityManager.find(User.class, selectedUser.getUsername());
      
       user.setConfirmPassword(user.getPassword());
       setOriginalPassword(user.getPassword());
       return "userEdit";
      
       } catch (EntityNotFoundException e) {
       facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO,
       "Common.error.notFound", selectedUser.getFullName());
       return "userList";
       }
       }
      
      
      
       @End
       public String update() {
       try {
       entityManager.merge(user);
      
       } catch (OptimisticLockException e) {
       user = currentUser;
       facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_ERROR, "Common.error.concurrency");
       return null;
       }
       facesMessages.addFromResourceBundle(FacesMessage.SEVERITY_INFO,
       "Common.message.updated", user.getFullName());
      
       return "userList";
       }
      
      
       @End
       public String cancel() {
       return "userList";
       }
      
      
      


      Maybe you are thinking that this post should be done in Ajax4JSF forum, but I'm not sure about this, because it seems like a em.merge() is done, but I don't know by whom. Anyway I hope you can give some hints in order to solve this problem.


      Thanks in advance.