-->
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.  [ 3 posts ] 
Author Message
 Post subject: Lazy initialization happening when it should not.
PostPosted: Wed Sep 10, 2003 11:02 pm 
Senior
Senior

Joined: Sun Aug 31, 2003 3:14 pm
Posts: 151
Location: Earth (at the moment)
I am getting absurd proxy usage from reasons I can't begin to fathom.
I apologize that I have not posted a "main method" to JIRA as I simply haven't had time because I have been trying to get my project done any way I can first but I keep getting stuck on the weird problems with the results I am getting from Hibernate (I guess this is a chicken and egg type problem, do I keep pounding away at the problem to try to get my project working or do I let the project slide while I figure out how to post to JIRA which might result in a solution to my problems which would get the project working).

Loading the same persisted class hierarchy, just with different values (different records), using the same method, I am getting varying results as to whether or not the objects are "initialized" or just proxies which will generate the infamous LazyInitializationException when I try to use them later in a View (MVC).

I have the following mappings (unabridged):
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>

   <!-- WorksheetProduct -->
   <class name="com.fgl.ina.costestimation.WorksheetProduct" table="worksheet_product">
      <id name="ID" type="integer" column="worksheet_product_id" unsaved-value="0">
         <generator class="net.sf.hibernate.id.IdentityGenerator"/>
      </id>
      <many-to-one name="parentWorksheet"       column="worksheet_id" not-null="true"/>
      <property    name="productID"             column="ina_prod_id"  type="long"  not-null="false"/>
      <property    name="unitOfMeasureQuantity" column="uom_qty"      type="float" not-null="false"/>

      <bag name="costFactors" table="worksheet_factor" lazy="false" inverse="true" cascade="all-delete-orphan" order-by="worksheet_factor_id" outer-join="true">
         <key column="worksheet_product_id"/>
<!--         <index column="worksheet_factor_id" type="string"/>-->
         <one-to-many class="com.fgl.ina.costestimation.WorksheetFactor"/>
      </bag>
   </class>

   <!-- WorksheetHeader -->
   <class name="com.fgl.ina.costestimation.WorksheetHeader" table="worksheet_header">
      <id name="worksheetID" type="integer" column="worksheet_id" unsaved-value="0">
         <generator class="net.sf.hibernate.id.IdentityGenerator"/>
      </id>
      <property name="description"       column="description"         type="string"/>
      <property name="vendor"            column="vendor_no"           type="string"    not-null="true"/>
      <property name="status"            column="status"              type="short"     not-null="true"/>
<!--      <many-to-one name="status" class="com.fgl.ina.costestimation.lookups.WorksheetStatus"-->
<!--         column="status" update="false" insert="false" cascade="none" outer-join="true"/>-->
      <property name="createdBy"         column="created_by"          type="string"    not-null="true"/>
      <property name="createdDate"       column="created_date"        type="timestamp" not-null="true"/>
      <property name="revisedDate"       column="last_revision_date"  type="timestamp" not-null="true"/>
      <property name="foreignStatus"     column="foreign_status"      type="short"     not-null="true"/>
<!--      <bag name="validForeignStatuses" lazy="false" cascade="none" outer-join="true" order-by="foreign_status">-->
<!--         <many-to-many class="com.fgl.ina.costestimation.lookups.ForeignExchangeStatus" outer-join="true"/>-->
<!--      </bag>   -->
      <property name="foreignContractNo" column="foreign_contract_no" type="long"      not-null="true"/>
      <property name="comments"          column="comments"            type="string"/>

      <map name="products" table="worksheet_product" lazy="true" inverse="true" cascade="all" order-by="worksheet_product_id" outer-join="true">
         <key column="worksheet_id"/>
         <index column="worksheet_product_id" type="string"/>
         <one-to-many class="com.fgl.ina.costestimation.WorksheetProduct"/>
      </map>
   </class>

   <!-- WorksheetFactor -->
   <class name="com.fgl.ina.costestimation.WorksheetFactor" table="worksheet_factor">
      <id name="ID" type="integer" column="worksheet_factor_id" unsaved-value="0">
         <generator class="net.sf.hibernate.id.IdentityGenerator"/>
      </id>
      <many-to-one name="parentProduct"   column="worksheet_product_id" not-null="true"/>
      <property    name="costFactorID"    column="cost_factor_id"    type="integer"/>
      <property    name="calculatedType"  column="calculated_type"   type="short"/>
      <property    name="costFactorValue" column="cost_factor_value" type="float"/>
      <property    name="foreignAmount"   column="foreign_amount"    type="float"/>
      <property    name="currencyType"    column="currency_type"     type="short"/>
      <property    name="exchangeRate"    column="exchange_rate"     type="float"/>
      <property    name="proratingType"   column="prorating_type"    type="short"/>
      <many-to-one name="costFactor" class="com.fgl.ina.costestimation.CostFactor" insert="false" update="false"
         cascade="none" column="cost_factor_id" outer-join="true"/>
   </class>

   <!-- Cost Factor Description -->
   <class name="com.fgl.ina.costestimation.CostFactorDescription" table="cost_factor_description" mutable="false">
      <id name="costFactorID" type="integer" column="cost_factor_id">
         <generator class="net.sf.hibernate.id.IdentityGenerator"/>
      </id>
      <property name="language"    column="locale"      type="string"/>
      <property name="description" column="description" type="string"/>
   </class>

   <!-- Cost Factor -->
   <class name="com.fgl.ina.costestimation.CostFactor" table="cost_factor" mutable="false">
      <id name="costFactorID" type="integer" column="cost_factor_id">
         <generator class="net.sf.hibernate.id.IdentityGenerator"/>
      </id>

      <set name="calculatedTypeOptions" lazy="false" cascade="none" where="locale='en'" outer-join="true">
         <key column="cost_factor_id"/>
<!--         <index column="allowable_type" type="integer"/>-->
         <one-to-many class="com.fgl.ina.costestimation.lookups.CalculatedTypeLookup"/>
      </set>
      <set name="currencyTypeOptions" lazy="false" cascade="none" outer-join="true">
         <key column="cost_factor_id"/>
<!--         <index column="allowable_type" type="integer"/>-->
         <one-to-many class="com.fgl.ina.costestimation.lookups.CurrencyTypeLookup"/>
      </set>
      <set name="proratingTypeOptions" lazy="false" cascade="none" where="locale='en'" outer-join="true">
         <key column="cost_factor_id"/>
<!--         <index column="allowable_type" type="integer"/>-->
         <one-to-many class="com.fgl.ina.costestimation.lookups.ProratingTypeLookup"/>
      </set>

      <bag name="descriptions" lazy="false" cascade="none" table="cost_factor_descriptions" where="locale='en'" outer-join="true">
         <key column="cost_factor_id"/>
<!--         <index column="locale" type="string"/>-->
         <one-to-many class="com.fgl.ina.costestimation.CostFactorDescription"/>
      </bag>
   </class>
</hibernate-mapping>


I have recently made one mapping have lazy=true but that hasn't changed the strange results I get (if anything it has possibly made things worse?).

It seems that if I have more than one record for the first level Map of WorksheetProduct that I can be guaranteed that the various Sets and Bags further down the hierarchy will be proxies. However, if I only have one record for WorksheetProduct everything in the hierarchy loads correctly (which it didn't used to do when the Map of WorksheetProducts was set as lazy=false, then I used to get a proxy for that Map anyway, and also for the Bag/Map I have on it, and then only on the Bag of descriptions further down the hierarchy but consistently all of the time for any record even though they were all set as lazy=false).

I have tried all kinds of clueless hacking about with configuration properties such as batch_size, max_fetch_depth, use_outer_join, etc. that have not affect things that I can tell.

Here is the current incarnation of my hibernate.properties file:
Code:
######################
### Query Language ###
######################

## define query language constants / function names

hibernate.query.substitutions true 1, false 0, yes 'Y', no 'N'

## package imports

hibernate.query.imports net.sf.hibernate.test, net.sf.hibernate.eg



#################
### Platforms ###
#################

## JNDI Datasource
hibernate.connection.datasource ina
hibernate.connection.username <deleted>
hibernate.connection.password <deleted>

## MS SQL Server
hibernate.dialect net.sf.hibernate.dialect.SybaseDialect


#################################
### Hibernate Connection Pool ###
#################################

hibernate.connection.pool_size 0
hibernate.statement_cache.size 25



###########################
### C3P0 Connection Pool###
###########################

#hibernate.c3p0.max_size 2
#hibernate.c3p0.min_size 2
#hibernate.c3p0.timeout 5000
#hibernate.c3p0.max_statements 100
#hibernate.c3p0.validate false



###################################
### Apache DBCP Connection Pool ###
###################################

## connection pool

#hibernate.dbcp.maxActive 100
#hibernate.dbcp.whenExhaustedAction 1
#hibernate.dbcp.maxWait 120000
#hibernate.dbcp.maxIdle 10

## prepared statement cache

#hibernate.dbcp.ps.maxActive 100
#hibernate.dbcp.ps.whenExhaustedAction 1
#hibernate.dbcp.ps.maxWait 120000
#hibernate.dbcp.ps.maxIdle 100

## optional query to validate pooled connections:

#hibernate.dbcp.validationQuery select 1 from dual
#hibernate.dbcp.testOnBorrow true
#hibernate.dbcp.testOnReturn false



##############################
### Proxool Connection Pool###
##############################

## Properties for external configuration of Proxool

#hibernate.proxool.pool_alias pool1

## Only need one of the following

#hibernate.proxool.existing_pool true
#hibernate.proxool.xml proxool.xml
#hibernate.proxool.properties proxool.properties

## Or, alternatively, all of these
## Standard configuration properties of Proxool

#hibernate.proxool.house-keeping-sleep-time 30000
#hibernate.proxool.house-keeping-test-sql
#hibernate.proxool.maximum-connection-count 4
#hibernate.proxool.maximum-connection-lifetime 4
#hibernate.proxool.simultaneous-build-throttle 2
#hibernate.proxool.maximum-active-time 500
#hibernate.proxool.minimum-connection-count 2
#hibernate.proxool.fatal-sql-exception
#hibernate.proxool.prototype-count
#hibernate.proxool.statistics
#hibernate.proxool.recently-started-threshold
#hibernate.proxool.overload-without-refusal-lifetime



#################################
### Plugin ConnectionProvider ###
#################################

## use a custom ConnectionProvider (if not set, Hibernate will choose a built-in ConnectionProvider using hueristics)

#hibernate.connection.provider_class net.sf.hibernate.connection.DriverManagerConnectionProvider
#hibernate.connection.provider_class net.sf.hibernate.connection.DatasourceConnectionProvider
#hibernate.connection.provider_class net.sf.hibernate.connection.C3P0ConnectionProvider
#hibernate.connection.provider_class net.sf.hibernate.connection.DBCPConnectionProvider
#hibernate.connection.provider_class net.sf.hibernate.connection.ProxoolConnectionProvider



#######################
### Transaction API ###
#######################

## the Transaction API abstracts application code from the underlying JTA or JDBC transactions

#hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory
#hibernate.transaction.factory_class net.sf.hibernate.transaction.JDBCTransactionFactory

#hibernate.transaction.factory_class net.sf.hibernate.transaction.JRun4TransactionManagerLookup


## to use JTATransactionFactory, Hibernate must be able to locate the UserTransaction in JNDI
## default is java:comp/UserTransaction

#jta.UserTransaction jta/usertransaction
#jta.UserTransaction javax.transaction.UserTransaction
#jta.UserTransaction UserTransaction


## to use JTATransactionFactory with JCS caching, Hibernate must be able to obtain the JTA TransactionManager

#hibernate.transaction.manager_lookup_class net.sf.hibernate.transaction.JBossTransactionManagerLookup
#hibernate.transaction.manager_lookup_class net.sf.hibernate.transaction.WeblogicTransactionManagerLookup
#hibernate.transaction.manager_lookup_class net.sf.hibernate.transaction.WebSphereTransactionManagerLookup
#hibernate.transaction.manager_lookup_class net.sf.hibernate.transaction.OrionTransactionManagerLookup
#hibernate.transaction.manager_lookup_class net.sf.hibernate.transaction.ResinTransactionManagerLookup



##############################
### Miscellaneous Settings ###
##############################

## print all generated SQL to the console
hibernate.show_sql true


## specify a JDBC isolation level
#hibernate.connection.isolation 4


## set the JDBC fetch size
#hibernate.jdbc.fetch_size 25


## set the maximum JDBC 2 batch size (a nonzero value enables batching)
#hibernate.jdbc.batch_size 0
hibernate.jdbc.batch_size 30


## enable use of JDBC 2 scrollable ResultSets (specifying a Dialect will cause Hibernate to use a sensible default)
#hibernate.jdbc.use_scrollable_resultset true


## use streams when writing binary types to / from JDBC
hibernate.jdbc.use_streams_for_binary true


## specify a default schema for unqualified tablenames
#hibernate.default_schema test


## use a custom stylesheet for XML generation (if not specified, hibernate-default.xslt will be used)
#hibernate.xml.output_stylesheet C:/Hibernate/net/sf/hibernate/hibernate-default.xslt


## enable outerjoin fetching (specifying a Dialect will cause Hibernate to use sensible default)
#hibernate.use_outer_join false

## set the maximum depth of the outer join fetch tree
# ???
hibernate.max_fetch_depth 75

## enable CGLIB reflection optimizer (enabled by default)
#hibernate.cglib.use_reflection_optimizer false



############
### JNDI ###
############

## specify a JNDI name for the SessionFactory

hibernate.session_factory_name ina_session_factory


## Hibernate uses JNDI to bind a name to a SessionFactory and to look up the JTA UserTransaction;
## if hibernate.jndi.* are not specified, Hibernate will use the default InitialContext() which
## is the best approach in an application server

#JRun4
hibernate.jndi.class jrun.naming.JRunContextFactory
hibernate.jndi.url localhost\:2914



The method I am using to load the class Hierarchy described in the mapping above is as follows:
Code:
   /**
    * Retrieves a persisted worksheet (i.e. {@link WorksheetHeader} instance) identified by the specified ID.
    * @param worksheetID the ID of the worksheet to retrieve
    * @return the <code>WorksheetHeader</code> instance.
    * @throws Exception
    */
   public static WorksheetHeader getWorksheetHeaderByID(int worksheetID, String language) throws Exception {
      Session session = DataAccessServiceHelper.getSession();
      WorksheetHeader returnHeader = null;
      Criteria criteria;
      try {
         criteria = session.createCriteria(WorksheetHeader.class).add(
               Expression.eq(WORKSHEET_ID, new Integer(worksheetID)));
//         criteria = criteria.createAlias("products", "prod");
//         criteria = criteria.add(Expression.isNull("prod."+PRODUCT_ID));
//         criteria = criteria.createAlias("prod.costFactors", "costs");
//         criteria = criteria.createAlias("costs.costFactor.calculatedTypeOptions", "calcTypes");
//         criteria = criteria.createAlias("costs.costFactor.proratingTypeOptions", "proTypes");
         criteria = criteria.createCriteria("products").add(Expression.not(Expression.isNotNull(PRODUCT_ID)));
////         criteria = criteria.createCriteria("costFactors");
//         criteria = criteria.add(Expression.eq("calcTypes.language", language));
//         criteria = criteria.add(Expression.eq("proTypes.language", language));
//         criteria = criteria.createCriteria("costs.costFactor.descriptions");
//         criteria = criteria.add(Expression.eq("language", language));

         returnHeader = (WorksheetHeader)criteria.list().get(0);
      // TODO: remove idiotic force of initialization to stop stupid LazyInitializationException in Hibernate 2.1b2
//         Hibernate.initialize(returnHeader);
         Hibernate.initialize(returnHeader.getProducts());
         // this is really stupid...
         returnHeader.toString(); // dumb, very dumb
//         Hibernate.initialize(((WorksheetFactor)((WorksheetProduct)returnHeader.getProducts().toArray()[0]).getCostFactors().toArray()[0]).getCostFactor().getDescriptions());

         // load the unkeyed worksheet status description seperately
         returnHeader.setStatusDescription(getWorksheetStatus(returnHeader.getStatus(), language));
         // load the unkeyed foreign exchange status descriptions seperately
         returnHeader.setValidForeignStatuses(getWorksheetStatusDescriptions(ForeignExchangeStatus.class, language));

      } catch (Throwable t) {
         LogFactory.getLog(WorksheetService.class).error("Could not load worksheet " + worksheetID, t);
      } finally {
         session.close();
      }
      return returnHeader;
   }

This is complete with commented out weird things I have done to try to force initialization to happen and Criteria stuff that doesn't work in the version I have available to me (2.1beta3b). The returnHeader.toString() line calls a custom toString() method which "prints" out all of the properties and their values which results in navigating through all of my classes that have an overridden toString() thereby forcing initialization of everything.

If I comment out that stupid toString() call I will get LazyInitializationExceptions from any WorksheetHeader instance that has more than one WorksheetProduct in it's Map of WorksheetProducts, but only on the one's with more than one record, the one's with only one record will initialize just fine.

This is what is happening right now, every time I change one little seemingly unrelated (obviously not truly unrelated) thing (such as one lazy=false to lazy=true) the spurious use of proxies for some records and not for others will change to "new" locations and/or types.

I thought perhaps it was related to joining and so I tried bumping up the max_fetch_depth but that didn't seem to have an effect.

Other information (to save reading the config closely); I am using JRun4, SQL Server 2000, and the macromedia driver for SQL Server that comes with JRun4 (I have also tried the j-netdirect driver running under Tomcat 5.0.11 with the same results so I'm sure it has something to do with Hibernate or my configuration thereof and not my container). I am using the latest Struts and the various Struts taglibs. I am using Log4J 1.2.8. I am using the exact jar files that Hibernate ships with copied verbatum from the Hibernate lib folder into my web apps lib folder.

I don't know what else to say but please ask if you need more info and please help if you can.

I've run out of time and I'm at wits end.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 11, 2003 12:34 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Why don't you just use the "open session in view" pattern?


Top
 Profile  
 
 Post subject: open session in view pattern
PostPosted: Thu Sep 11, 2003 1:19 am 
Senior
Senior

Joined: Sun Aug 31, 2003 3:14 pm
Posts: 151
Location: Earth (at the moment)
Quote:
Why don't you just use the "open session in view" pattern?


Thank-you, I will look into it.

I am concerned that it may not be a direction I want to go in, especially just to work around a problem that should have a more direct solution.
I am currently inclined to agree with this quote from the wiki:
Quote:
And if you are building a genuinely enterprise-class app, you probably shouldn't be using this pattern, as it kind of breaks MVC anyway.

from David Benoff at http://hibernate.bluemars.net/43.8.html

Thank-you for all your hard work.
Sincerely,
David Duffy


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 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.