LazyInitializationException at @ManyToMany
dandii Jan 11, 2011 9:31 AMHi,
I have a problem regarding a LazyInitializationException in my application. For my application I implemented application user and groups: AppUser and AppGroup. connected are both with a @ManyToMany relation.
My Problem is, that I can not update entities of the type AppUser.
For both types I implemented an EntityHome including methods: persist(), update(), create(), find(), and an EntityList with getResultList(), getResultCount().
My xhtml Files are userList.xhtml for a List of all entities - user.xhtml as the view for one entity and - userEdit for adding or updating an entity (and respectively: groupList.xhtml, group.xhtml and groupEdit.xhtml).
Therefore I created the following entities:
@Entity
@Table(name = "app_group")
public class AppGroup extends BaseEntity implements Serializable {
private String name;
private Set<AppUser> users;
protected Long id;
public AppGroup(){
super();
users = new HashSet<AppUser>(0);
}
@Id
@Column(name = "id",nullable = false)
@GeneratedValue(strategy = GenerationType.AUTO,generator = "app_group_seq_gen")
@SequenceGenerator(name = "app_group_seq_gen",sequenceName = "app_group_seq")
@Override
public Long getId(){return this.id;}
public void setId(Long id) { this.id = id;}
@Column(name = "name")
@NotNull
public String getName(){ return name; }
public void setName(String name){ this.name = name;}
public void setUsers(Set<AppUser> users){ this.users = users; }
@ManyToMany(cascade ={CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.EAGER)
@JoinTable(name="AppUser_AppGroup",
joinColumns={@JoinColumn(name="group_id")},
inverseJoinColumns={@JoinColumn(name="user_id")})
public Set<AppUser> getUsers() { return users; }
}@Entity
@Table(name = "app_user")
@NamedQueries( { @NamedQuery(name = AppUser.findAppUserByExternalId,query = "Select a FROM AppUser a WHERE a.externalId=:externalId") })
public class AppUser extends BaseEntity implements Serializable
{
private static final long serialVersionUID = 3065922756639551646L;
//Named query
public static final String findAppUserByExternalId = "findAppUserByExternalId";
private String firstName;
private String lastName;
private Long externalId;
private List<AppGroup> groups;
public AppUser() {
super();
groups = new ArrayList<AppGroup>();
}
@Id
@Column(name = "id",nullable = false)
@GeneratedValue(strategy = GenerationType.AUTO,generator = "app_user_seq_gen")
@SequenceGenerator(name = "app_user_seq_gen",sequenceName = "app_user_seq")
@Override
public Long getId(){ return this.id; }
public void setGroups(List<AppGroup> groups){ this.groups = groups; }
@ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, fetch=FetchType.EAGER)
@JoinTable(name="AppUser_AppGroup",
joinColumns={@JoinColumn(name="user_id")},
inverseJoinColumns={@JoinColumn(name="group_id")})
public List<AppGroup> getGroups(){ return groups; }
// more getters and setters
}Some of my .xhtml files:
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:s="http://jboss.com/products/seam/taglib" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:rich="http://richfaces.org/rich" xmlns:a4j="http://richfaces.org/a4j" template="/layout/template.xhtml">
<f:metadata>
<f:viewParam name="userId" value="#{appUserHome.id}"/>
</f:metadata>
<ui:define name="body">
<rich:panel>
<f:facet name="header">#{messages.user}</f:facet>
<ui:decorate template="/layout/display.xhtml">
<ui:define name="label">#{messages.name}</ui:define>
<h:outputText value="#{appUserHome.instance.firstName}"/>
</ui:decorate>
<!-- other attributes -->
<ui:decorate template="/layout/display.xhtml">
<ui:define name="label">#{messages.groups}</ui:define>
<rich:list id="list" var="group" value="#{appUserHome.instance.groups}" type="unordered" title="Group">
<h:outputText value="#{group.name}" />
</rich:list>
</ui:decorate>
<div style="clear:both"/>
</rich:panel>
<div class="actionButtons">
<h:form>
<h:button outcome="/user/userEdit" id="edit" value="#{messages.edit}" >
<f:param name="cid" value="#{conversation.id}"/>
</h:button>
<h:commandButton value="#{messages.done}" action="#{appUserHome.cancel('/user/userList')}" immediate="true" />
<h:commandButton id="delete" value="#{messages.delete}" action="#{appUserHome.remove}" immediate="true" />
</h:form>
</div>
</ui:define>
</ui:composition>and the userEdit.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:rich="http://richfaces.org/rich" xmlns:csv="http://richfaces.org/csv" xmlns:a4j="http://richfaces.org/a4j" template="/layout/template.xhtml">
<f:metadata> <f:viewParam name="userId" value="#{appUserHome.id}" /> </f:metadata>
<ui:define name="body">
<h:form id="user" styleClass="edit">
<rich:panel>
<f:facet name="header">#{appUserHome.managed ? 'Edit' : 'Add'} #{messages.user}</f:facet>
<ui:decorate template="/layout/edit.xhtml">
<ui:define name="label">#{messages.firstName}</ui:define>
<ui:param name="inputid" value="firstname"/>
<ui:param name="required" value="true"/>
<h:inputText id="firstname" styleClass="inputEdit" value="#{appUserHome.instance.firstName}">
<csv:beanValidator/>
</h:inputText>
</ui:decorate>
<ui:decorate template="/layout/edit.xhtml">
<ui:define name="label">#{messages.lastName}</ui:define>
<ui:param name="inputid" value="lastname"/>
<ui:param name="required" value="true"/>
<h:inputText id="lastname" styleClass="inputEdit" value="#{appUserHome.instance.lastName}">
<csv:beanValidator/>
</h:inputText>
</ui:decorate>
<ui:decorate template="/layout/edit.xhtml">
<ui:define name="label">#{messages.externalId}</ui:define>
<ui:param name="inputid" value="extId"/>
<ui:param name="required" value="true"/>
<h:inputText id="extId" styleClass="inputEdit" value="#{appUserHome.instance.externalId}">
<csv:beanValidator/>
</h:inputText>
</ui:decorate>
<ui:decorate template="/layout/edit.xhtml">
<ui:define name="label">#{messages.groups}</ui:define>
<h:selectManyListbox id="groups" converter="baseEntityConverter"
value="#{appUserHome.instance.groups}" size="3">
<f:selectItems value="#{appGroupList.all}"
var="group" itemLabel="#{group.name}" itemValue="#{group}" />
</h:selectManyListbox>
</ui:decorate>
<div style="clear: both" />
</rich:panel>
<div class="actionButtons">
<h:commandButton id="save" value="#{messages.save}" action="#{appUserHome.persist}" rendered="#{!appUserHome.managed}" />
<h:commandButton id="update" value="#{messages.update}" action="#{appUserHome.update}" rendered="#{appUserHome.managed}" />
<h:button id="cancelEdit" value="#{messages.cancel}" outcome="/user/user" rendered="#{appUserHome.managed}" >
<f:param name="cid" value="#{conversation.id}"/>
</h:button>
<h:button id="cancelAdd" value="#{messages.cancel}" outcome="/user/userList" rendered="#{!appUserHome.managed}" />
</div>
</h:form>
</ui:define>
</ui:composition>I get the LazyInitializationException using the h:button with the id update in the userEdit.xhtml.