I'm including as much relevent information as makes sense below, but here's the gist: using hibernate 4.0.x in a Swing application. Because it's a Swing application, I'm trying to load the entire object graph into memory upfront, i.e. I turn off all lazy loading.
My Payee object is mapped to a collection of payment objects. When the collection is set on a payee object, I want to iterate over it and register a PropertyChangeSupport with every payment bean in the collection as well as calculate some totals:
Code:
public void setPayments(Set payments)
{
if( this.payments == payments )
return;
unregisterUpdateListeners(this.payments);
if( observablePayments != null )
observablePayments.getHandler().removePostModificationListener(paymentsListener);
this.payments = payments;
this.observablePayments = ObservableSet.decorate(payments);
paymentsListener = new PaymentsListener();
if( observablePayments != null)
observablePayments.getHandler().addPostModificationListener(paymentsListener);
registerUpdateListeners(payments);
updateDosCodeTotals();
}
the setPayments method above is mapped to the payments property in OlzPayments.hbm.xml
Code:
<set name="payments" cascade="all-delete-orphan" fetch="join" inverse="true">
<key column="payee_id"/>
<one-to-many class="edu.ucsd.som.onlinez.business.OlzPaymentDetail"/>
</set>
(also see below)
The problem is (and this development is recent, I didn't use to have this issue before I upgraded from 2.x), that when setPayments is being called I get "LazyInitializationException: illegal access to loading collection"
I understand that the root cause of it is that the collection passed to setPayments isn't being finished initializing. But here's a list a questions I'd like to get answers to:
1) Why is it a LayInitializationException when I don't do any lazy loading?
2) Why would Hibernate give me an unitialized collection? Is there a way to tell it not to?
3) How do I change the design to work around this problem? How do I find out when a collection is done loading and do the necessary housekeeping stuff.
4) How do I do the above and still keep the business layer unaware of Hibernate and all the persistence related shenanigans ?
Thanks
Dmitry
Hibernate version: 3.0.5
Mapping documents:Code:
<hibernate-mapping>
<class name="edu.ucsd.som.onlinez.business.OlzPayee" table="olz_payee" where="current_pay_period='true'" lazy="false">
<cache usage="read-write"/>
<id name="_id" column="payee_id">
<generator class="native"/>
</id>
<many-to-one name="payrollTitle" column="title_code"
class="edu.ucsd.som.business.PayrollTitle" fetch="join" update="false"/>
<many-to-one name="employee" column="ucsd_id"
class="edu.ucsd.som.business.payments.PaymentEmployee" access="field"
fetch="join" update="false" />
<many-to-one name="division" column="division_id"
class="edu.ucsd.som.onlinez.business.OlzDivision"
update="false" fetch="join" />
<set name="payments" cascade="all-delete-orphan" fetch="join" inverse="true">
<key column="payee_id"/>
<one-to-many class="edu.ucsd.som.onlinez.business.OlzPaymentDetail"/>
</set>
</class>
</hibernate-mapping>
Code:
<hibernate-mapping>
<class name="edu.ucsd.som.onlinez.business.OlzPaymentDetail" table="olz_pmnt_detail" where="dos_code='BYZ'" lazy="false">
<id name="_id" column="detail_id" type="long">
<generator class="native"/>
</id>
<version name="lastUpdate" column="update_ts" type="timestamp"/>
<property name="index" column="index_num" type="string" access="field"/>
<property name="amount" column="amount" type="float" access="field"/>
<property name="preloadable" column="preloadable" type="boolean"/>
<property name="employeeId" column="employee_id" type="string"/>
<many-to-one name="payPeriod" column="pay_period_id"
class="edu.ucsd.som.business.PayPeriod" access="field" fetch="join" />
<many-to-one name="dosCode" column="dos_code"
class="edu.ucsd.som.business.DosCode" fetch="join" />
<many-to-one name="payee" column="payee_id"
class="edu.ucsd.som.onlinez.business.OlzPayee" fetch="join" />
<many-to-one name="owner" column="owner_id"
class="edu.ucsd.som.portal.PortalUser" fetch="join" />
<many-to-one name="olzType" column="z_type_id" fetch="join" />
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():
Full stack trace of any exception that occurs:
Quote:
edu.ucsd.som.util.DataStoreLoadException: org.hibernate.PropertyAccessException: Exception occurred inside setter of edu.ucsd.som.onlinez.business.OlzPayee.payments
at edu.ucsd.som.hibernate.AbstractHibernate3DataStore.load(AbstractHibernate3DataStore.java:191)
at edu.ucsd.som.util.PersistentObject.load(PersistentObject.java:194)
at edu.ucsd.som.onlinez.business.TestOlzPayee.testLoad(TestOlzPayee.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at com.intellij.rt.execution.junit2.JUnitStarter.main(JUnitStarter.java:31)
Caused by: org.hibernate.PropertyAccessException: Exception occurred inside setter of edu.ucsd.som.onlinez.business.OlzPayee.payments
at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:51)
at org.hibernate.tuple.AbstractTuplizer.setPropertyValues(AbstractTuplizer.java:207)
at org.hibernate.tuple.PojoTuplizer.setPropertyValues(PojoTuplizer.java:176)
at org.hibernate.persister.entity.BasicEntityPersister.setPropertyValues(BasicEntityPersister.java:2919)
at org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:113)
at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:530)
at org.hibernate.loader.Loader.doQuery(Loader.java:436)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:218)
at org.hibernate.loader.Loader.loadEntity(Loader.java:1345)
at org.hibernate.loader.entity.EntityLoader.load(EntityLoader.java:116)
at org.hibernate.loader.entity.EntityLoader.load(EntityLoader.java:101)
at org.hibernate.persister.entity.BasicEntityPersister.load(BasicEntityPersister.java:2471)
at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:351)
at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:332)
at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:113)
at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:151)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:79)
at org.hibernate.impl.SessionImpl.load(SessionImpl.java:603)
at org.hibernate.impl.SessionImpl.load(SessionImpl.java:596)
at edu.ucsd.som.hibernate.AbstractHibernate3DataStore.load(AbstractHibernate3DataStore.java:183)
... 20 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:40)
... 39 more
Caused by: org.hibernate.LazyInitializationException: illegal access to loading collection
at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:172)
at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:48)
at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:134)
at edu.ucsd.som.business.payments.Payee.registerUpdateListeners(Payee.java:158)
at edu.ucsd.som.business.payments.Payee.setPayments(Payee.java:104)
at edu.ucsd.som.onlinez.business.OlzPayee.setPayments(OlzPayee.java:56)
... 44 more
Name and version of the database you are using:MySQL 4.0
The generated SQL (show_sql=true):Quote:
[main] DEBUG org.hibernate.SQL - select olzpayee0_.payee_id as payee1_11_, olzpayee0_.title_code as title2_13_11_, olzpayee0_.ucsd_id as ucsd3_13_11_, olzpayee0_.division_id as division4_13_11_, payrolltit1_.code as code0_, payrolltit1_.name as name4_0_, payrolltit1_.ttl_title_unit_code as ttl3_4_0_, payrolltit1_.ttl_personnel_program_code as ttl4_4_0_, payrolltit1_.annual_max as annual5_4_0_, payrolltit1_.annual_min as annual6_4_0_, paymentemp2_.employee_id as employee1_1_, paymentemp2_.employee_id as employee1_11_1_, paymentemp2_.last_name as last2_11_1_, paymentemp2_.first_name as first3_11_1_, paymentemp2_.annual_rate as annual4_11_1_, paymentemp2_.hire_date as hire5_11_1_, paymentemp2_.home_department_id as home6_11_1_, department3_.som_department_id as som1_2_, department3_.name as name2_2_, department3_.som_department_id as som1_2_2_, department3_.dbo_ucsd_id as dbo3_2_2_, department3_.major_group_id as major4_2_2_, olzdivisio4_.division_id as division1_3_, olzdivisio4_.name as name3_3_, olzdivisio4_.department_id as department4_3_3_, olzdepartm5_.som_department_id as som1_4_, olzdepartm5_.name as name2_4_, olzdepartm5_.som_department_id as som1_2_4_, olzdepartm5_.major_group_id as major4_2_4_, olzdepartm5_.dbo_ucsd_id as dbo3_2_4_, olzmajorgr6_.som_major_group_id as som1_5_, olzmajorgr6_.name as name1_5_, payments7_.payee_id as payee9_13_, payments7_.detail_id as detail1_13_, payments7_.detail_id as detail1_6_, payments7_.update_ts as update2_12_6_, payments7_.index_num as index3_12_6_, payments7_.amount as amount12_6_, payments7_.preloadable as preloada5_12_6_, payments7_.employee_id as employee6_12_6_, payments7_.pay_period_id as pay7_12_6_, payments7_.dos_code as dos8_12_6_, payments7_.payee_id as payee9_12_6_, payments7_.owner_id as owner10_12_6_, payments7_.z_type_id as z11_12_6_, payperiod8_.tpp_period_id as tpp1_7_, payperiod8_.tpp_period_type_code as tpp2_14_7_, payperiod8_.tpp_period_begin_date as tpp3_14_7_, payperiod8_.tpp_period_end_date as tpp4_14_7_, payperiod8_.tpp_period_pay_date as tpp5_14_7_, payperiod8_.tpp_period_cutoff_date as tpp6_14_7_, payperiod8_.tpp_period_extract_date as tpp7_14_7_, payperiod8_.som_editing_cutoff_date as som8_14_7_, payperiod8_.tpp_period_standard_hours as tpp9_14_7_, doscode9_.code as code8_, doscode9_.title as title7_8_, portaluser10_.core_user_id as core1_9_, portaluser10_.name as name8_9_, portaluser10_.first_name as first3_8_9_, portaluser10_.last_name as last4_8_9_, portaluser10_.email as email8_9_, portaluser10_.employee_id as employee6_8_9_, ztype11_.z_type_id as z1_10_, ztype11_.name as name15_10_, ztype11_.code as code15_10_ from olz_payee olzpayee0_ left outer join som_payroll_title payrolltit1_ on olzpayee0_.title_code=payrolltit1_.code left outer join pmnt_employee paymentemp2_ on olzpayee0_.ucsd_id=paymentemp2_.employee_id left outer join som_department department3_ on paymentemp2_.home_department_id=department3_.som_department_id left outer join som_division olzdivisio4_ on olzpayee0_.division_id=olzdivisio4_.division_id left outer join som_department olzdepartm5_ on olzdivisio4_.department_id=olzdepartm5_.som_department_id left outer join som_major_group olzmajorgr6_ on olzdepartm5_.major_group_id=olzmajorgr6_.som_major_group_id left outer join olz_pmnt_detail payments7_ on olzpayee0_.payee_id=payments7_.payee_id left outer join som_pay_period payperiod8_ on payments7_.pay_period_id=payperiod8_.tpp_period_id left outer join som_dos_code doscode9_ on payments7_.dos_code=doscode9_.code left outer join core_user portaluser10_ on payments7_.owner_id=portaluser10_.core_user_id left outer join som_z_type ztype11_ on payments7_.z_type_id=ztype11_.z_type_id where olzpayee0_.payee_id=? and olzpayee0_.current_pay_period='true'
Debug level Hibernate log excerpt: