Announcement Announcement Module
Collapse
No announcement yet.
fetching strategy Problem Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • fetching strategy Problem

    In order to prevent the loading of the whole graph of every associated object,
    I've configured all my associations fetching to lazy.

    here is an example of what I've done:

    My StructureSocieteGestion class is associated to my Structure
    class by à many to one
    association.

    Here are fragment codes of both Classes and corresponding mappng files

    public class Structure implements Serializable
    {
    private String codeStructure;
    //some other properties
    // getters, setter ,equals and hashcode

    public Structure(){}
    }

    corresponding mapping fragment :
    <hibernate-mapping
    >
    <class
    name="com.nxbp.nis.biosphere.model.Structure"
    table="T_Structure"
    lazy="true" >
    <id
    name="codeStructure"
    column="CodeStructure"
    type="java.lang.String"
    >
    <generator class="assigned">
    </generator>
    </id>

    <property
    name="procedureAllegee"
    type="boolean"
    />
    // some other properties

    Now my StructureSocieteGestion class and mapping:

    public class StructureSocieteGestion implements Serializable{
    private Long identifiant;
    private Structure structure;
    //some other properties
    // getters, setter ,equals and hashcode,default constructor
    }

    the corresponding mapping fragment

    <hibernate-mapping
    >
    <class
    name="com.nxbp.nis.biosphere.model.StructureSociet eGestion"
    table="T_Structure_SocieteGestion"
    >
    <id
    name="identifiant"
    column="Identifiant"
    type="java.lang.Long"
    >
    <generator class="identity">
    </generator>
    </id>

    //some properties ...
    //the structure many to one association
    <many-to-one
    name="structure"
    class="com.nxbp.nis.biosphere.model.Structure"
    cascade="none"
    outer-join="auto"
    access="property"
    >
    <column
    name="CodeStructure"
    />
    </many-to-one>
    >

    In my StructureSocieteGestionDAO, I'm using a fetchMode upon the criteria api when I need to override the default fetching strategy.
    It works fine (here is an example)

    public Object doInHibernate(Session session) throws HibernateException
    {
    Criteria criteria = session.createCriteria(TStructureSocieteGestion.cl ass);
    criteria.add(Expression.eq("structure.codeStructur e", codeStructure));
    criteria.add(Expression.le("dateDebutValidite", now));
    criteria.add(Expression.ge("dateFinValidite", now));
    criteria.setFetchMode("structure",FetchMode.EAGER) ; return criteria.uniqueResult();

    The problem arise when I try to load object from my StructureDAO side.
    I'm doing like that :

    public Structure findById(String codeStructure) throws FinderException
    {
    Structure result=null;
    try
    {
    result=(Structure)getHibernateTemplate().load(Stru cture.class,codeStructure);
    }

    I'm getting an LazyInitialisationException when this method executes.

    Can someone tells me how I could workaround this problem.

    Meissa

  • #2
    Can you post the stack trace (the relevant part at least)?

    Comment


    • #3
      Re: fetching strategy Problem

      Originally posted by meissa
      In order to prevent the loading of the whole graph of every associated object,
      I've configured all my associations fetching to lazy.

      here is an example of what I've done:

      My StructureSocieteGestion class is associated to my Structure
      class by à many to one
      association.

      Here are fragment codes of both Classes and corresponding mappng files

      public class Structure implements Serializable
      {
      private String codeStructure;
      //some other properties
      // getters, setter ,equals and hashcode

      public Structure(){}
      }

      corresponding mapping fragment :
      <hibernate-mapping
      >
      <class
      name="com.nxbp.nis.biosphere.model.Structure"
      table="T_Structure"
      lazy="true" >
      <id
      name="codeStructure"
      column="CodeStructure"
      type="java.lang.String"
      >
      <generator class="assigned">
      </generator>
      </id>

      <property
      name="procedureAllegee"
      type="boolean"
      />
      // some other properties

      Now my StructureSocieteGestion class and mapping:

      public class StructureSocieteGestion implements Serializable{
      private Long identifiant;
      private Structure structure;
      //some other properties
      // getters, setter ,equals and hashcode,default constructor
      }

      the corresponding mapping fragment

      <hibernate-mapping
      >
      <class
      name="com.nxbp.nis.biosphere.model.StructureSociet eGestion"
      table="T_Structure_SocieteGestion"
      >
      <id
      name="identifiant"
      column="Identifiant"
      type="java.lang.Long"
      >
      <generator class="identity">
      </generator>
      </id>

      //some properties ...
      //the structure many to one association
      <many-to-one
      name="structure"
      class="com.nxbp.nis.biosphere.model.Structure"
      cascade="none"
      outer-join="auto"
      access="property"
      >
      <column
      name="CodeStructure"
      />
      </many-to-one>
      >

      In my StructureSocieteGestionDAO, I'm using a fetchMode upon the criteria api when I need to override the default fetching strategy.
      It works fine (here is an example)

      public Object doInHibernate(Session session) throws HibernateException
      {
      Criteria criteria = session.createCriteria(TStructureSocieteGestion.cl ass);
      criteria.add(Expression.eq("structure.codeStructur e", codeStructure));
      criteria.add(Expression.le("dateDebutValidite", now));
      criteria.add(Expression.ge("dateFinValidite", now));
      criteria.setFetchMode("structure",FetchMode.EAGER) ; return criteria.uniqueResult();

      The problem arise when I try to load object from my StructureDAO side.
      I'm doing like that :

      public Structure findById(String codeStructure) throws FinderException
      {
      Structure result=null;
      try
      {
      result=(Structure)getHibernateTemplate().load(Stru cture.class,codeStructure);
      }

      I'm getting an LazyInitialisationException when this method executes.

      Can someone tells me how I could workaround this problem.

      Meissa
      Here is the stack trace:
      ERROR [LazyInitializer] Exception initializing proxy
      net.sf.hibernate.HibernateException: Could not initialize proxy - the owning Session was closed
      at net.sf.hibernate.proxy.LazyInitializer.initialize( LazyInitializer.java:47)
      at net.sf.hibernate.proxy.LazyInitializer.initializeW rapExceptions(LazyInitializer.java:60)
      at net.sf.hibernate.proxy.LazyInitializer.getImplemen tation(LazyInitializer.java:164)
      at net.sf.hibernate.proxy.CGLIBLazyInitializer.interc ept(CGLIBLazyInitializer.java:108)
      at com.nxbp.nis.biosphere.model.TStructure$$EnhancerB yCGLIB$$b11432dc.toString(<generated>)
      at com.nxbp.biosphere.business.TestStructureDAO.testF indStructure(TestStructureDAO.java:52)

      The method which is called :

      public TStructure findById(String codeStructure) throws FinderException
      {
      TStructure result=null;
      try
      {
      result=(TStructure)getHibernateTemplate().load(TSt ructure.class,codeStructure);
      }
      catch (Exception e)
      {
      String errorMessage=" Echec du chargement de la structure"+codeStructure;
      log.error(e+errorMessage);

      throw new FinderException(errorMessage,e);
      }
      return result;
      }

      As you can see, I even can't load any data from my Dao because The lazy mapping attribute is set lo lazy.
      As I undestood, this was for associated object and not for the owning object itself.
      I really don't nkow how to solve this problem.

      Meissa

      Comment


      • #4
        Lazy loading problems usually appear because the workflow of the hibernate session and the object is not known very well. You are fetching an associated Structure (retrieving it eagerly) but the object is visible only inside the 1st level cache (same session) and for the object is associated with.
        Your DAO (containing the HibernateTemplate) does load the object but as a proxy (load() always returns proxies, find returns entites) - unless you are using the OpenInViewFilter/Interceptor, the session is closed right after the template method ends execution.
        That's why the lazy-loading error - the structure object you are trying to find inside the dao is not related to the associated structure object.

        I recommend you take a look at the Hibernate examples both in HB and Spring distribution and take a look at OpenSessionInView filter/interceptor. A great book on HB and ORM in general is Hiberante In Action - read it!. Also you can look at AppFuse which is a popular Spring-Hibernate start up application.

        P.S. no, I'm not in any way associated with mr. raible

        Comment


        • #5
          Originally posted by costin
          Lazy loading problems usually appear because the workflow of the hibernate session and the object is not known very well. You are fetching an associated Structure (retrieving it eagerly) but the object is visible only inside the 1st level cache (same session) and for the object is associated with.
          Your DAO (containing the HibernateTemplate) does load the object but as a proxy (load() always returns proxies, find returns entites) - unless you are using the OpenInViewFilter/Interceptor, the session is closed right after the template method ends execution.
          That's why the lazy-loading error - the structure object you are trying to find inside the dao is not related to the associated structure object.
          I recommend you take a look at the Hibernate examples both in HB and Spring distribution and take a look at OpenSessionInView filter/interceptor. A great book on HB and ORM in general is Hiberante In Action - read it!. Also you can look at AppFuse which is a popular Spring-Hibernate start up application.

          P.S. no, I'm not in any way associated with mr. raible
          Take à look at the complete mapping below. You'll see that the StructureDAO is related to the Structure Object.
          I have in my hand HIA, and the feature I'm trying to apply is described in chapter 7, p 259(fetching associations strategy).
          The curious thing in this is that I'm setting fetching strategy for associated object at runtime within the criteria api(as described) in the book and it works fine.
          But when i try to load the Structure object itself, because of the lazy mode which is set to true, it fails. As if my DAO was not related to Structure object. I aggree, there is a bug somewhere in my mapping or my
          DAO code, but I'm tearing my hair to find it out.
          I'm posting the complete DAO and the Complete mapping. I'm really blocked by this problem:

          The Complete mapping :
          <?xml version="1.0" encoding="UTF-8"?>

          <!DOCTYPE hibernate-mapping PUBLIC
          "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
          "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

          <hibernate-mapping
          >
          <class
          name="com.nxbp.nis.biosphere.model.Structure"
          table="T_Structure"
          lazy="true"
          dynamic-update="true"
          dynamic-insert="true"
          select-before-update="false"
          optimistic-lock="version"
          >

          <id
          name="codeStructure"
          column="CodeStructure"
          type="java.lang.String"
          >
          <generator class="assigned">

          </generator>
          </id>

          <property
          name="procedureAllegee"
          type="boolean"
          update="true"
          insert="true"
          access="property"
          column="ProcedureAllegee"
          length="1"
          not-null="true"
          />



          <property
          name="pluraliteGerant"
          type="boolean"
          update="true"
          insert="true"
          access="property"
          column="PluraliteGerant"
          length="1"
          not-null="true"
          />



          <property
          name="dateDroitVote"
          type="java.util.Date"
          update="true"
          insert="true"
          access="property"
          column="DateDroitVote"
          length="23"
          />




          </class>

          </hibernate-mapping>

          The Complete DAO

          public class StructureDAO extends HibernateDaoSupport
          {
          private static Log log = LogFactory.getLog(StructureDAO.class);



          /**
          *
          */
          public StructureDAO()
          {

          }

          /**
          * Crée une entité de la table principale
          * @param structure
          * @return
          * @throws CreateStructureException
          */
          public Structure create(Structure structure) throws CreateStructureException
          {
          try
          {
          getHibernateTemplate().save(structure);
          }
          catch (DataAccessException e)
          {
          String errorMessage=" Echec de la creation de la structure "+structure.toString();
          log.error(e+errorMessage);

          throw new CreateStructureException(errorMessage,e);
          }

          return structure;
          }

          /**
          * modifie en base les informations de la table principale
          * @param structure
          * @return
          * @throws ModifyStructureException
          */

          public Structure modify(Structure structure) throws ModifyStructureException
          {
          try
          {
          getHibernateTemplate().saveOrUpdateCopy(structure) ;
          }
          catch (DataAccessException e)
          {
          String errorMessage=" Echec de la mise à jour de la structure "+structure.toString();
          log.error(e+errorMessage);

          throw new ModifyStructureException(errorMessage,e);
          }

          return structure;
          }

          /**
          * Retourne une entité <code>Structure</code>
          * @param codeStructure
          * @return
          * @throws FinderException
          */
          public Structure findById(String codeStructure) throws FinderException
          {
          Structure result=null;
          try
          {
          result=(Structure)getHibernateTemplate().load(Stru cture.class,codeStructure);
          }
          catch (Exception e)
          {
          String errorMessage=" Echec du chargement de la structure"+codeStructure;
          log.error(e+errorMessage);

          throw new FinderException(errorMessage,e);
          }
          return result;
          }

          }

          Comment


          • #6
            meissa I don't think you understood my message correctly. Your dao is fine - it simply delegates all your calls to HibernateTemplate - the dao or the mapping is not the problem.
            Let's call Structure class A and StructureSocieteGenstion class B. B has 1-to-many relation with B.
            When you are using eager fetching you are retrieving eagerly (you initialize) the B and associated A set relationship within that session.

            However, if you use only the DAO for A, then the object that you retrieve even if it's the same as one associated with B which was retrieved before, it's a proxy (not initialized). Because proxies depend on their session, the object cannot be rezolved unless the session is open. That's why, you are able to find the object but when you use it, you get an exception, the associated session was closed (that's why I mentioned looking at OpenSessionInView).

            Try as a quick hack, inside your DAO to initialize the object like this:
            Code:
             public Structure findById&#40;String codeStructure&#41; throws FinderException
            &#123;
            Structure result=null;
            try
            &#123;
            result=&#40;Structure&#41;getHibernateTemplate&#40;&#41;.load&#40;Structure.class,codeStructure&#41;;
            
            // initialize object
            Hibernate.initialize&#40;result&#41;;
            
            &#125;
            catch &#40;Exception e&#41;
            &#123;
            String errorMessage=" Echec du chargement de la structure"+codeStructure;
            log.error&#40;e+errorMessage&#41;;
            
            throw new FinderException&#40;errorMessage,e&#41;;
            &#125;
            return result;
            &#125;
            Another alternative would be to use the OpenSessionInView interceptor/filter.

            As I said before, load() returns proxies if lazy is set to true while find() always returns entites.

            Comment


            • #7
              Fetching strategy problem

              Originally posted by costin
              meissa I don't think you understood my message correctly. Your dao is fine - it simply delegates all your calls to HibernateTemplate - the dao or the mapping is not the problem.
              Let's call Structure class A and StructureSocieteGenstion class B. B has 1-to-many relation with B.
              When you are using eager fetching you are retrieving eagerly (you initialize) the B and associated A set relationship within that session.

              However, if you use only the DAO for A, then the object that you retrieve even if it's the same as one associated with B which was retrieved before, it's a proxy (not initialized). Because proxies depend on their session, the object cannot be rezolved unless the session is open. That's why, you are able to find the object but when you use it, you get an exception, the associated session was closed (that's why I mentioned looking at OpenSessionInView).

              Try as a quick hack, inside your DAO to initialize the object like this:
              Code:
               public Structure findById&#40;String codeStructure&#41; throws FinderException
              &#123;
              Structure result=null;
              try
              &#123;
              result=&#40;Structure&#41;getHibernateTemplate&#40;&#41;.load&#40;Structure.class,codeStructure&#41;;
              
              // initialize object
              Hibernate.initialize&#40;result&#41;;
              
              &#125;
              catch &#40;Exception e&#41;
              &#123;
              String errorMessage=" Echec du chargement de la structure"+codeStructure;
              log.error&#40;e+errorMessage&#41;;
              
              throw new FinderException&#40;errorMessage,e&#41;;
              &#125;
              return result;
              &#125;
              Another alternative would be to use the OpenSessionInView interceptor/filter.

              As I said before, load() returns proxies if lazy is set to true while find() always returns entites.
              Costin you gave me the solution when you said
              "load() returns proxy while find always return entities !""

              add Hibernate.initialise() method gave me the same result.
              I did not want to go on OpenSessioninView just to make a load.
              here is what I've changed and it works fine.

              public Structure findById(final String codeStructure) throws FinderException
              {
              Structure result = null;
              try
              {
              result = (Structure) getHibernateTemplate().execute(new HibernateCallback()
              {
              public Object doInHibernate(Session session) throws HibernateException
              {
              Criteria criteria = session.createCriteria(Structure.class);
              criteria.add(Expression.eq("codeStructure", codeStructure));
              return criteria.uniqueResult();

              }
              });
              }
              catch (Exception e)
              {
              log.error(e);
              throw new FinderException(e);
              }

              return result;

              }

              Can you please give me your opinion about this code.
              Anyway, you've helped me a lot. Thank you very much.

              Meissa

              Comment


              • #8
                Hibernate.initialize(result);
                Should initialize the object.
                Anyways, about the code unless you want to customize the way you retrieve the objects, get rid of it - it's just a wrapper around the hibernateTemplate. In my project I use a generic DAO which extends the hibernateTemplate support in order to add some methods.
                The less code you have, the less you have to debug.

                Comment


                • #9
                  fetching strategy problem -Generic DAO design pattern

                  Originally posted by costin
                  Hibernate.initialize(result);
                  Should initialize the object.
                  In my project I use a generic DAO which extends the hibernateTemplate support in order to add some methods.
                  The less code you have, the less you have to debug.
                  Costin,
                  I have the same need.
                  I'm starting a new project with an existing database which have more than 100 tables(exactly 142)
                  I was thinking about Having a generic DAO with the same purpose of your.

                  In my design thinking :
                  1)My GenericDAO would be an asbtract class that will extend HibernateDaoSupport .
                  2) Il will be extended by all other dao.

                  What do you think about this?
                  Could you share some of your experience about generic DAO design pattern.
                  What should go there and what should not go there.

                  Could you send me some base code about your generic dao so as I can start mine with some experienced background.

                  thanks in advance.

                  Meissa

                  Comment


                  • #10
                    Could you send me some base code about your generic dao so as I can start mine with some experienced background.
                    There is no need for such a thing - these issues are a lot simpler then you think. That's why I recommended the examples from the Spring distribution and AppFuse - they contain exactly what you want.

                    Comment

                    Working...
                    X