3 Replies Latest reply on Jan 20, 2011 4:29 AM by dandii

    LazyInitializationException at @ManyToMany

    dandii

      Hi,


      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.

        • 1. Re: LazyInitializationException at @ManyToMany
          dandii

          Hi again,


          I could isolate the exception in:


          <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>


          • 2. Re: LazyInitializationException at @ManyToMany
            ovigica

            appGroupList as i understand it's bean for list informations. Please correct me if i'm wrong.You populated appGroupList.all with a reference to users from AppGroup. I think that AppGroup does not have session scope. And the entity since was on request, was dispossed. You had the reference to that hibernate collection on session. After you get that collection, Hibernate Proxy was called, and since that collection was empty, he tried to populate it from the database ...  but ..suprize ...no session. That's why this exception appeared(LazyInitializationException). My solution is:


            -populate another collection on session form that collection. Attention ..is copyAll, or iterate and add every element ...do not keep a reference to thae hoibernate collection. At save or update ,...you will repopulate the hibernate collection and ...all will work fine at persist or flush


            Good look!

            • 3. Re: LazyInitializationException at @ManyToMany
              dandii

              hi,
              the solution is the attribute collectionType




                                  <h:selectManyListbox id="groups" 
                                      collectionType="java.util.ArrayList"
                                      converter="baseEntityConverter"
                                      value="#{appUserHome.instance.groups}" size="3">
                                     <f:selectItems value="#{appGroupList.all}"
                                             var="group"
                                             itemLabel="#{group.name}" itemValue="#{group}" />
                                  </h:selectManyListbox>