Troubles With Many-to-Many
thetikigod.tiki_god.mail.com Oct 16, 2008 3:55 PMHey guys,
Im using JBoss AS 4.3.2 GA, Seam 2.0.2.SP1, and MySQL.
Ive got two entities with a many to many relation between them. When I try to update the relational table, the changes dont persist. Also, when I edit one of the entities, all the corresponding entries in the relational table get aced. I have a hack/work around for that but I would much rather do it the right way. Here is my code:
User entity:
package com.burris.essapp.model; // imports @Entity @Name( "user" ) public class User implements Serializable { private String userId; private String password; private String firstName; private String lastName; private String email; private long phone; private List<Role> roles; private List<Role> unassignedRoles; public User() { super(); } public User( String userId, String password ) { super(); this.userId = userId; this.password = password; } public User( String userId, String password, String firstName, String lastName ) { super(); this.userId = userId; this.password = password; this.firstName = firstName; this.lastName = lastName; } public User( String userId, String password, String firstName, String lastName, String email, long phone ) { super(); this.userId = userId; this.password = password; this.firstName = firstName; this.lastName = lastName; this.email = email; this.phone = phone; } @Id public String getUserId() { return userId; } public void setUserId( String userId ) { this.userId = userId; } public String getPassword() { return password; } public void setPassword( String password ) { this.password = password; } public String getFirstName() { return firstName; } public void setFirstName( String firstName ) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName( String lastName ) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail( String email ) { this.email = email; } public Long getPhone() { return phone; } public void setPhone( Long phone ) { this.phone = phone; } @ManyToMany( fetch = FetchType.EAGER ) @JoinTable( name = "UserRole", joinColumns = { @JoinColumn( name = "userId" ) }, inverseJoinColumns = { @JoinColumn( name = "roleId" ) } ) public List<Role> getRoles() { if (roles == null) { roles = new ArrayList<Role>(); } return this.roles; } public void setRoles( List<Role> roles ) { this.roles = roles; } @Transient public List<Role> getUnassignedRoles() { return unassignedRoles; } public void setUnassignedRoles( List<Role> unassignedRoles ) { this.unassignedRoles = unassignedRoles; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((email == null) ? 0 : email.hashCode()); result = prime * result + ((firstName == null) ? 0 : firstName.hashCode()); result = prime * result + ((lastName == null) ? 0 : lastName.hashCode()); result = prime * result + ((password == null) ? 0 : password.hashCode()); result = prime * result + (int) (phone ^ (phone >>> 32)); result = prime * result + ((userId == null) ? 0 : userId.hashCode()); return result; } @Override public boolean equals( Object obj ) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final User other = (User) obj; if (email == null) { if (other.email != null) return false; } else if (!email.equals( other.email )) return false; if (firstName == null) { if (other.firstName != null) return false; } else if (!firstName.equals( other.firstName )) return false; if (lastName == null) { if (other.lastName != null) return false; } else if (!lastName.equals( other.lastName )) return false; if (password == null) { if (other.password != null) return false; } else if (!password.equals( other.password )) return false; if (phone != other.phone) return false; if (userId == null) { if (other.userId != null) return false; } else if (!userId.equals( other.userId )) return false; return true; } @Override public String toString() { return this.userId; }
UserManagerBean:
package com.burris.essapp.action; // imports @Stateful @Name( "usermanager" ) @Scope( CONVERSATION ) public class UserManagerBean implements UserManager { @In( create = true ) @Out private User user; @Out private List<User> users; @PersistenceContext private EntityManager em; @Factory( "users" ) public void getAll() { this.users = em.createQuery( "select u from User u" ).getResultList(); } @Begin public String beginCreate() { return null; } @End public String endCreate() { Role employee = em.find( Role.class, "employee" ); this.user.getRoles().add( employee ); this.em.persist( user ); this.user = new User(); this.users = em.createQuery( "select u from User u" ).getResultList(); return null; } @Begin public String beginEdit( Object user ) { if (user instanceof User) { this.user = (User) user; } else { throw new ClassCastException( "Expected a User object." ); } return null; } @End public String endEdit() { User tempUser = this.em.find( User.class, this.user.getUserId() ); this.user.setRoles( tempUser.getRoles() ); this.em.merge( user ); |this.users = em.createQuery( "select u from User u" ).getResultList(); return null; } @Begin public String beginRoleEdit( User user ) { if (user instanceof User) { this.user = (User) user; List<Role> unassignedRoles = em.createQuery( "select r from Role r" ).getResultList(); unassignedRoles.removeAll( this.user.getRoles() ); this.user.setUnassignedRoles( unassignedRoles ); } else { throw new ClassCastException( "Expected a User object." ); } return null; } @End public String endRoleEdit() { User tempUser = this.em.find( User.class, this.user.getUserId() ); tempUser.setRoles( this.user.getRoles() ); this.em.merge( tempUser ); this.user = new User(); // this.users = em.createQuery( "select u from User u" ).getResultList(); return null; } @Begin public String beginDelete( Object user ) { if (user instanceof User) { this.user = (User) user; } else { throw new ClassCastException( "Expected a User object." ); } return null; } @End public String endDelete() { User tempUser = em.merge( user ); this.em.remove( tempUser ); this.users = em.createQuery( "select u from User u" ).getResultList(); this.user = new User(); return null; } @End public String cancel() { this.users = em.createQuery( "select u from User u" ).getResultList(); this.user = new User(); return null; } @Destroy @Remove public void destroy() { } public User getUser() { return user; } public void setUser( User user ) { this.user = user; } public List<User> getUsers() { return users; } public void setUsers( List<User> users ) { this.users = users; } }
console.xhtml:
<rich:tab label="User Manager"> <ui:include src="userModalPanels.xhtml"></ui:include> <h:commandButton id="openCreateUserPanel" value="Add User" action="#{usermanager.beginCreate}"> <rich:componentControl for="createUserPanel" attachTo="openCreateUserPanel" operation="show" event="onclick"/> </h:commandButton> <h:form> <rich:dataTable id="usersTable" value="#{users}" var="u" rows="10"> <f:facet name="header"> <rich:datascroller id="userTableScroller1" for="usersTable" ajaxSingle="false" reRender="userTableScroller2" /> </f:facet> <rich:column> <f:facet name="header"><h:outputText value="User ID" /></f:facet> <h:outputText value="#{u.userId}" /> </rich:column> <rich:column> <f:facet name="header"><h:outputText value="Last Name" /></f:facet> <h:outputText value="#{u.lastName}" /> </rich:column> <rich:column> <f:facet name="header"><h:outputText value="First Name" /></f:facet> <h:outputText value="#{u.firstName}" /> </rich:column> <rich:column> <f:facet name="header"><h:outputText value="Phone" /></f:facet> <h:outputText value="#{u.phone}" /> </rich:column> <rich:column> <f:facet name="header"><h:outputText value="Email" /></f:facet> <h:outputText value="#{u.email}" /> </rich:column> <rich:column> <f:facet name="header"><h:outputText value="Actions" /></f:facet> <a4j:commandButton value="Edit" action="#{usermanager.beginEdit(u)}" oncomplete="Richfaces.showModalPanel('editUserPanel');" reRender="userInfoToEdit" /> <a4j:commandButton value="Roles" action="#{usermanager.beginRoleEdit(u)}" oncomplete="Richfaces.showModalPanel('editRolesUserPanel');" reRender="userRolesToEdit" /> <a4j:commandButton value="Delete" action="#{usermanager.beginDelete(u)}" oncomplete="Richfaces.showModalPanel('deleteUserPanel');" reRender="userInfoToDelete" /> </rich:column> <f:facet name="footer"> <rich:datascroller id="userTableScroller2" for="usersTable" ajaxSingle="false" reRender="userTableScroller1" /> </f:facet> </rich:dataTable> </h:form> </rich:tab>| Modal Panels: | <rich:modalPanel id="editUserPanel" width="300" height="100"> <f:facet name="header"> <h:outputText value="Edit User Information" /> </f:facet> <h:outputText value="Fields marked with an * are required." /> <s:div id="userInfoToEdit"> <h:form> <rich:spacer height="15" /> <h:panelGrid columns="2"> <h:outputText value="Editing: " /> <h:outputText value="#{user.userId}" /> <rich:spacer height="15" /> <rich:spacer height="15" /> <h:outputText for="password" value="*Password:" /> <h:inputSecret id="password" value="#{user.password}" redisplay="true" /> <h:outputText for="lastName" value="Last Name:" /> <h:inputText id="lastName" value="#{user.lastName}" /> <h:outputText for="firstName" value="First Name:" /> <h:inputText id="firstName" value="#{user.firstName}" /> <h:outputText for="phone" value="Phone:" /> <h:inputText id="phone" value="#{user.phone}" /> <h:outputText for="email" value="Email:" /> <h:inputText id="email" value="#{user.email}" /> <h:outputText for="userId" value="" /> <h:inputHidden id="userId" value="#{user.userId}" /> </h:panelGrid> <rich:spacer height="15" /> <center> <h:commandButton value="Save" action="#{usermanager.endEdit}" oncomplete="Richfaces.hideModalPanel('editUserPanel'); return false" /> <h:commandButton value="Cancel" action="#{usermanager.cancel}" oncomplete="Richfaces.hideModalPanel('editUserPanel'); return false" /> </center> </h:form> </s:div> </rich:modalPanel> <rich:modalPanel id="editRolesUserPanel" width="300" height="100"> <f:facet name="header"> <h:outputText value="Edit User Roles" /> </f:facet> <s:div id="userRolesToEdit"> <h:outputText for="userId" value="Editing: " /> <h:outputText id="userId" value="#{user.userId}" /> <rich:spacer height="15" /> <rich:listShuttle id="userShuttle" sourceValue="#{user.unassignedRoles}" targetValue="#{user.roles}" var="r" converter="org.jboss.seam.ui.EntityConverter" fastOrderControlsVisible="false" orderControlsVisible="false"> <h:column> <h:outputText value="#{r.roleId}" /> </h:column> <a4j:support event="onlistchanged" reRender="userRolesToEdit" /> </rich:listShuttle> </s:div> <rich:spacer height="15" /> <center> <s:button value="Save" action="#{usermanager.endRoleEdit}" onclick="Richfaces.hideModalPanel('editRolesUserPanel'); return false" /> <s:button value="Cancel" action="#{usermanager.cancel}" onclick="Richfaces.hideModalPanel('editRolesUserPanel'); return false" /> </center> </rich:modalPanel>
Ive looked over this for a while and I cant find my error and it is getting frustrating.