-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: Many to many relations, saving the Set
PostPosted: Fri Feb 12, 2010 1:01 pm 
Newbie

Joined: Wed Aug 01, 2007 4:53 pm
Posts: 11
I have this application i am writing were i have some many to many relations. I have problems storing those...
For example a case from my application:
I have students and classes. Each student can be part of multiple classes and every class can have multiple students.
Students are stored in a table called "leerlingen" and classes are stored in "klassen". The relationship is stored in leerling_klassen where lln_id is the ID of the student en klas_id is the id of the class.

THis is m current code:

Klas:

Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="be.eschool.model.domain">
  <class name="Klas" table="klassen">
        <id name="id" column="id">
         <generator class="native"/>
      </id>
      <property name="naam"/>
      <set name="leerlingen" table="leerling_klassen" cascade="all" lazy="true">
         <key column="klas_id"/>
         <many-to-many column="lln_id" class="Leerling"/>
      </set>
  </class>
</hibernate-mapping>


Leerling:

Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="be.eschool.model.domain">
  <class name="Leerling" table="leerlingen">
        <id name="id" column="id">
         <generator class="native"/>
      </id>
      <property name="naam"/>
      <property name="voornaam"/>
      <property name="adres"/>
      <property name="gemeente"/>
      <property name="pcode"/>
      
      <set name="klassen" table="leerling_klassen" cascade="all" lazy="true">
         <key column="lln_id"/>
         <many-to-many column="klas_id" class="Klas" order-by="naam"/>
      </set>
  </class>
</hibernate-mapping>


Klas.java

Code:
package be.eschool.model.domain;


import java.util.Set;

public class Klas {
   
   private int id;
   private String naam;
   private boolean selected;
   
   private Set<Leerling> leerlingen;
   
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getNaam() {
      return naam;
   }
   public void setNaam(String naam) {
      this.naam = naam;
   }
   public boolean isSelected() {
      return selected;
   }
   public void setSelected(boolean selected) {
      this.selected = selected;
   }
   
   public Set<Leerling> getLeerlingen() {
      leerlingen.size();
      return leerlingen;
   }
   public void setLeerlingen(Set<Leerling> leerlingen) {
      this.leerlingen = leerlingen;
   }

   public String toString()
   {
      return this.getNaam();
   }
}



Leerling.java

Code:
package be.eschool.model.domain;

import java.util.HashSet;
import java.util.Set;

public class Leerling
{
   private int id;
   private String voornaam,naam,adres,gemeente,pcode;
   private boolean selected = false;
   
   private Set<Klas> klassen = new HashSet<Klas>();
   
   public String getNaam() {
      return naam;
   }

   public void setNaam(String naam) {
      this.naam = naam;
   }

   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }
   
   public Leerling(){}

   public String getVoornaam() {
      return voornaam;
   }

   public void setVoornaam(String voornaam) {
      this.voornaam = voornaam;
   }
   
   public boolean isSelected()
   {
      return this.selected;
   }
   
   public void setSelected(boolean sel)
   {
      this.selected = sel;
   }

   public String getAdres() {
      return adres;
   }

   public void setAdres(String adres) {
      this.adres = adres;
   }

   public String getGemeente() {
      return gemeente;
   }

   public void setGemeente(String gemeente) {
      this.gemeente = gemeente;
   }

   public String getPcode() {
      return pcode;
   }

   public void setPcode(String pcode) {
      this.pcode = pcode;
   }

   public Set<Klas> getKlassen() {
      klassen.size();
      return klassen;
   }

   public void setKlassen(Set<Klas> klassen) {
      this.klassen = klassen;
   }
}



When i want to add a class to a student:

Set classes = student.getKlassen();
classes.add(myKlas);
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
session.save(student);
session.getTransaction().commit();

I get an error:

Code:
16:26:22,492 ERROR [LazyInitializationException:42] failed to lazily initialize a collection of role: be.eschool.model.domai
.leerlingen, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: be.eschool.model.domain.Klas.le
en, no session or session was closed
        at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollecti
a:380)
        at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPers
Collection.java:372)
        at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:119)
        at org.hibernate.collection.PersistentSet.size(PersistentSet.java:162)
        at be.eschool.model.domain.Klas.getLeerlingen(Klas.java:34)
        at sun.reflect.GeneratedMethodAccessor135.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:169)
        at org.hibernate.tuple.entity.AbstractEntityTuplizer.getPropertyValue(AbstractEntityTuplizer.java:293)
        at org.hibernate.persister.entity.AbstractEntityPersister.getPropertyValue(AbstractEntityPersister.java:3595)
        at org.hibernate.engine.Cascade.cascade(Cascade.java:154)
        at org.hibernate.event.def.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:563)
        at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:423)
        at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:234)
        at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:715)
        at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:697)
        at org.hibernate.engine.CascadingAction$6.cascade(CascadingAction.java:268)
        at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:292)
        at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:240)
        at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:193)
        at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:320)
        at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:266)
        at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:243)
        at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:193)
        at org.hibernate.engine.Cascade.cascade(Cascade.java:154)
        at org.hibernate.event.def.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:563)
        at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:423)
        at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:234)
        at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:715)
        at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:697)
        at org.hibernate.engine.CascadingAction$6.cascade(CascadingAction.java:268)
        at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:292)
        at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:240)
        at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:193)
        at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:320)
        at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:266)
        at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:243)
        at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:193)
        at org.hibernate.engine.Cascade.cascade(Cascade.java:154)
        at org.hibernate.event.def.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:563)
        at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:423)
        at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:234)
        at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:715)
        at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:697)
        at org.hibernate.engine.CascadingAction$6.cascade(CascadingAction.java:268)
        at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:292)
        at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:240)
        at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:193)
        at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:320)
        at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:266)
        at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:243)
        at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:193)
        at org.hibernate.engine.Cascade.cascade(Cascade.java:154)
        at org.hibernate.event.def.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:563)
        at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:423)
        at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:234)
        at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:84)
        at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:705)
        at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:689)
        at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:693)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.jav

        at $Proxy223.merge(Unknown Source)
        at be.eschool.model.controller.LeerlingController.saveLeerling(LeerlingController.java:26)
        at be.eschool.beans.LeerlingEdit.submitListener(LeerlingEdit.java:257)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at org.apache.el.parser.AstValue.invoke(AstValue.java:172)
        at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276)
        at com.sun.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:68)
        at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:88)
        at javax.faces.event.ActionEvent.processListener(ActionEvent.java:77)
        at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:743)
        at javax.faces.component.UICommand.broadcast(UICommand.java:368)
        at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:447)
        at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:752)
        at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:97)
        at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:251)
        at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:117)
        at com.icesoft.faces.webapp.http.core.JsfLifecycleExecutor.apply(JsfLifecycleExecutor.java:17)
        at com.icesoft.faces.webapp.http.core.ReceiveSendUpdates.renderCycle(ReceiveSendUpdates.java:54)
        at com.icesoft.faces.webapp.http.core.ReceiveSendUpdates.service(ReceiveSendUpdates.java:42)
        at com.icesoft.faces.webapp.http.core.ViewBoundServer.service(ViewBoundServer.java:65)
        at com.icesoft.faces.webapp.http.core.RequestVerifier.service(RequestVerifier.java:44)
        at com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer$Matcher.serviceOnMatch(PathDispatcherServer.ja

        at com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer.service(PathDispatcherServer.java:19)
        at com.icesoft.faces.webapp.http.servlet.ThreadBlockingAdaptingServlet.service(ThreadBlockingAdaptingServlet.java:19
        at com.icesoft.faces.webapp.http.servlet.EnvironmentAdaptingServlet.service(EnvironmentAdaptingServlet.java:63)
        at com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet.service(MainSessionBoundServlet.java:139)
        at com.icesoft.faces.webapp.http.servlet.SessionDispatcher.service(SessionDispatcher.java:53)
        at com.icesoft.faces.webapp.http.servlet.PathDispatcher$Matcher.serviceOnMatch(PathDispatcher.java:52)
        at com.icesoft.faces.webapp.http.servlet.PathDispatcher.service(PathDispatcher.java:29)
        at com.icesoft.faces.webapp.http.servlet.MainServlet.service(MainServlet.java:82)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at com.icesoft.faces.webapp.xmlhttp.BlockingServlet.service(BlockingServlet.java:46)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
        at java.lang.Thread.run(Thread.java:595)
16:55:46,432 ERROR [SessionDispatcher:154] java.lang.IllegalStateException: getAttributeNames: Session already invalidated


I cal this code from liferay portal. It's a portlet
Hibernate version 3.2
TOmcat version 6

last my hibernate config:

Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
      "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
      "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
       <property name="hibernate.current_session_context_class">org.hibernate.context.ThreadLocalSessionContext</property>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.password"></property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost/eschool</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

       
        <mapping resource="be/eschool/model/domain/Leerling.hbm.xml" />
        <mapping resource="be/eschool/model/domain/Klas.hbm.xml" />
        <mapping resource="be/eschool/model/domain/Gemeente.hbm.xml" />
    </session-factory>
</hibernate-configuration>



When i don't change anything on the et and just change name or address of the student and than save it, everything works fine. No errors than. I only get the error if i change something on the set. Add or remove an item.


Top
 Profile  
 
 Post subject: Re: Many to many relations, saving the Set
PostPosted: Mon Feb 15, 2010 4:53 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
As you specified the same secondary table name "leerling_klassen" for both many-to-many declaration,
I deduct that you intend to map a BIDIRECTIONAL many to many relation.
(If you indend to have 2 unidirectional many to many relations, then you also need 2 different secondary table names)

Well, on bidirectional many-to-many relations it is mandatory to declare one side of the relation with the inverse attribute.
This is necessary in order to tell Hibernate which many-to-many declarations belong together and constitute one relation.

So the first thing to do is to correct the mapping....


Top
 Profile  
 
 Post subject: Re: Many to many relations, saving the Set
PostPosted: Mon Feb 15, 2010 6:27 am 
Newbie

Joined: Wed Aug 01, 2007 4:53 pm
Posts: 11
I corrected the mapping and it's working.
Also.. the save does work but i'm not happy with it...

I notice it's because of the lazy initialization. When i set lazy="false" on each set, everything seems to work just fine.
I'm using JSF and hibernate together so i guess it has something to do with the request and the hibernate session that is closed to early but i don't realy know how to solve this so i could use lazy initialization instead of non lazy...


Top
 Profile  
 
 Post subject: Re: Many to many relations, saving the Set
PostPosted: Mon Feb 15, 2010 10:41 am 
Beginner
Beginner

Joined: Wed Nov 21, 2007 8:02 am
Posts: 48
1)

Passero wrote:

When i want to add a class to a student:


Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
session.save(student);
session.getTransaction().commit();




Instead of the above, use the following

Session session = HibernateUtil.getSessionFactory().getCurrentSession();

session.update(student); // this will re attach your student.

Set classes = student.getKlassen();
classes.add(myKlas);
session.beginTransaction();
session.save(student);
session.getTransaction().commit();

Or

2)
define a filter that opens a session at the beginning of http request and closes at the end.
Code:
class HibernateSessionRequestFilter implements Filter
    {
        private SessionFactory sessionFactory;

        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
            ServletException
        {

            try
            {
                sessionFactory.getCurrentSession().beginTransaction();
                chain.doFilter(request, response);
                sessionFactory.getCurrentSession().getTransaction().commit();
            }
            catch (Throwable ex)
            {
                // Rollback only
                ex.printStackTrace();
                if (sessionFactory.getCurrentSession().getTransaction().isActive())
                    sessionFactory.getCurrentSession().getTransaction().rollback();
                // Let others handle it... maybe another interceptor for exceptions?
                throw new ServletException(ex);
            }
        }

        public void init(FilterConfig filterConfig) throws ServletException
        {
            sessionFactory = HibernateUtil.getSessionFactory();
        }

        public void destroy()
        {
        }
    }

And define the filer in the web.xml
Code:
<filter>
        <filter-name>HibernateFilter</filter-name>
        <filter-class>abc.xyz.HibernateSessionRequestFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>HibernateFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


Now you can just do this in your code
Code:
Set classes = student.getKlassen();
classes.add(myKlas);
session.beginTransaction();
session.save(student);


If you search for OpenSessionInViewFilter, you will find more about this pattern


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.