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.