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.