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: LazyInitializationEx when Update()
PostPosted: Mon Aug 07, 2006 7:28 pm 
Newbie

Joined: Mon Aug 07, 2006 6:40 pm
Posts: 12
Location: Atlanta, GA
I have a problem where an object is part of an IList<T> retrieved uasing the same session as it is updated and called on the ISession.Update() method, with a transaction around the Update().

In Nhibernate.Proxy.LazyInitializer at the Session property a value is being assigned and it differs from the previous ISessionImpl. The timestamp does not match the one used to retrieve the objects, nor another session I opened using the same factory. Does NHibernate create its own?

It appears to be related to he <many-to-one> mappings, the call stack indicates that the Plan class below is involved. But it is excluded from update in the mapping and the cascade has been set to just about all the options (all, none, save-update, no attribute specified) and it still tries to update the Plan.

It appears that the FK (Plan) objects are being read when package objects are being read. I thought this mapping would suppress this along with the
<property name="hibernate.max_fetch_depth">0</property>.


Perhaps the first step is to get the loading of the plans to stop.

The message in the exception is:
Illegally attempted to associate a proxy with two open Sessions


Thanks for the help, or even the appropriate RTFM redirect. I have, and I am not finding it.

Here are details requested:

Hibernate version: 1.2.0.1001 (Alpha May-28)

Mapping documents:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<class name="PRG.CPFS.Objects.Package,PRG.CPFS.Objects" table="package" lazy="true" dynamic-update="true" dynamic-insert="true">

<id name="PackageIdentifier" column="[package]" type="Int32" unsaved-value="0">
<generator class="assigned"/>
</id>
<property column="[package_type]" type="String" name="PackageType" not-null="true" length="10" />
<property column="[plan]" type="String" name="Plan" not-null="true" length="6" />
.
. [more properties]
.

<property column="[scenario]" type="Boolean" name="Scenario" not-null="true" />
<property column="[automated]" type="Boolean" name="Automated" not-null="true" />


<many-to-one name="StatusObject" class="PRG.CPFS.Objects.PackageStatus, PRG.CPFS.Objects" update="false" insert="false" cascade="all">
<column name="[status]" />
</many-to-one>
<many-to-one name="PlanObject" class="PRG.CPFS.Objects.Plan, PRG.CPFS.Objects" update="false" insert="false" cascade="all">
<column name="[plan]" />
</many-to-one>
<many-to-one name="PeriodTypeObject" class="PRG.CPFS.Objects.PeriodType, PRG.CPFS.Objects" update="false" insert="false" cascade="all">
<column name="[period_type]" />
</many-to-one>
</class>
</hibernate-mapping>


Code between sessionFactory.openSession() and session.close():

It updates the Status property and then through a DAL abstraction calls Session.Update on the object.

Full stack trace of any exception that occurs:
at NHibernate.Proxy.LazyInitializer.set_Session(ISessionImplementor value) in c:\net\nhibernate\nhibernate\src\NHibernate\Proxy\LazyInitializer.cs:line 211
at NHibernate.Impl.SessionImpl.ReassociateProxy(LazyInitializer li, INHibernateProxy proxy) in c:\net\nhibernate\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 1083
at NHibernate.Impl.SessionImpl.ReassociateIfUninitializedProxy(Object value) in c:\net\nhibernate\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 1015
at NHibernate.Impl.ProxyVisitor.ProcessEntity(Object value, EntityType entityType) in c:\net\nhibernate\nhibernate\src\NHibernate\Impl\ProxyVisitor.cs:line 19
at NHibernate.Impl.AbstractVisitor.ProcessValue(Object value, IType type) in c:\net\nhibernate\nhibernate\src\NHibernate\Impl\AbstractVisitor.cs:line 61
at NHibernate.Impl.AbstractVisitor.ProcessValues(Object[] values, IType[] types) in c:\net\nhibernate\nhibernate\src\NHibernate\Impl\AbstractVisitor.cs:line 30
at NHibernate.Impl.AbstractVisitor.Process(Object obj, IEntityPersister persister) in c:\net\nhibernate\nhibernate\src\NHibernate\Impl\AbstractVisitor.cs:line 82
at NHibernate.Impl.SessionImpl.DoUpdateMutable(Object obj, Object id, IEntityPersister persister) in c:\net\nhibernate\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 1649
at NHibernate.Impl.SessionImpl.DoUpdate(Object obj, Object id, IEntityPersister persister) in c:\net\nhibernate\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 1664
at NHibernate.Impl.SessionImpl.Update(Object obj) in c:\net\nhibernate\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 1505
at PRG.Common.NHibernate.DataAccessBase`1.Update(Object item, ISession session, ITransaction transaction) in C:\Documents and Settings\bsayles\My Documents\Visual Studio 2005\Projects\Client Reporting\PRG.Common.NHibernate\DataAccessBase.cs:line 225

Name and version of the database you are using:
MS SQL 2000 sp3

The generated SQL (show_sql=true):
SELECT this_.[package] as column1_0_, this_.[updated_by] as column15_53_0_, this_.[archived_date] as column9_53_0_, this_.[reviewer] as column19_53_0_, this_.[analyst] as column18_53_0_, this_.[removed] as column17_53_0_, this_.[created] as column12_53_0_, this_.[plan_year] as column11_53_0_, this_.[end_date] as column5_53_0_, this_.[period_type] as column6_53_0_, this_.[scenario] as column21_53_0_, this_.[expected_receipt_date] as column10_53_0_, this_.[updated] as column14_53_0_, this_.[created_by] as column13_53_0_, this_.[mailed_date] as column8_53_0_, this_.[period_num] as column7_53_0_, this_.[plan] as column3_53_0_, this_.[automated] as column22_53_0_, this_.[status] as column20_53_0_, this_.[begin_date] as column4_53_0_, this_.[package_type] as column2_53_0_, this_.[previous_package] as column16_53_0_ FROM package this_ WHERE this_.[status] = @p0 and this_.[removed] = @p1

This one appears okay.

SELECT plan0_.[plan] as column1_0_, plan0_.[automated] as column13_58_0_, plan0_.[active] as column10_58_0_, plan0_.[plan_type] as column8_58_0_, plan0_.[year_end] as column2_58_0_, plan0_.[suspended] as column11_58_0_, plan0_.[created] as column4_58_0_, plan0_.[created_by] as column5_58_0_, plan0_.[priority] as column3_58_0_, plan0_.[non_standard_plan_year_period] as column9_58_0_, plan0_.[updated_by] as column7_58_0_, plan0_.[fileset] as column12_58_0_, plan0_.[updated] as column6_58_0_ FROM [plan] plan0_ WHERE plan0_.[plan]=@p0

Why this is being done, I need to find out. with fetch set at 0 it should not, I thought.

Debug level Hibernate log excerpt:

The pertinent parts appear to be:

19:12:37,082 DEBUG [InitializeEntitiesAndCollections] {NHibernate.Loader.Loader.InitializeEntitiesAndCollections(c:\net\nhibernate\nhibernate\src\NHibernate\Loader\Loader.cs:513)} total objects hydrated: 1950
19:12:37,082 DEBUG [InitializeEntity] {NHibernate.Impl.SessionImpl.InitializeEntity(c:\net\nhibernate\nhibernate\src\NHibernate\Impl\SessionImpl.cs:2834)} resolving associations for: [PRG.CPFS.Objects.Package#13000]
19:12:37,082 DEBUG [DoLoadByClass] {NHibernate.Impl.SessionImpl.DoLoadByClass(c:\net\nhibernate\nhibernate\src\NHibernate\Impl\SessionImpl.cs:2462)} loading [Plan#001022]
19:12:37,691 DEBUG [DoLoadByClass] {NHibernate.Impl.SessionImpl.DoLoadByClass(c:\net\nhibernate\nhibernate\src\NHibernate\Impl\SessionImpl.cs:2462)} loading [PackageStatus#AUTOSTART]
19:12:37,863 DEBUG [DoLoadByClass] {NHibernate.Impl.SessionImpl.DoLoadByClass(c:\net\nhibernate\nhibernate\src\NHibernate\Impl\SessionImpl.cs:2462)} loading [PeriodType#D]

This shows the many-to-one are non-lazy, and the IInterceptor.OnLoad in the source must be using a different session. But I need to stop this query altogether. To be continued:


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 08, 2006 12:09 am 
Newbie

Joined: Mon Aug 07, 2006 6:40 pm
Posts: 12
Location: Atlanta, GA
I think the load of the Plan object is actually happening when the Package object is being Update()ed; perhaps to enable dynamic-update on the plan object so it can be compared for changes if the the plan had never been called and populated. The proxy may in fact be lazy-loading, but the object is not there to be compared against so it is hydrated so it can be looked at. I may take dynamic-update off of the plan (the one on the many-to-one) but I am not confident that would work because the versioning logic many be involved.

Since in general I do not rely on NH to save the object graph yet, I may remove the many-to-one and handle the foreign key objects on my own. If I can't find a solution, this may be my chosen approach.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 08, 2006 12:06 pm 
Newbie

Joined: Mon Aug 07, 2006 6:40 pm
Posts: 12
Location: Atlanta, GA
I will now solve my own problem. We had set up a factory object for sessions and session factories to support HTTP and non-HTTP applications using the pattern documented heavily elsewhere to maintain consistency of the session used when objects were in an HTTP application. The accessor methods (implemented through a template class) have overloads that accept an explicit session or go to the factory for the active session. Since my non-HTTP application is multi-threaded, I have an explicit session for each thread.

But then I proceeded to call the accessor for the list that did not have a session argument, so the factory dutifully instantiated one for the list to be populated with. I then manipulated the list object, followed by a call to ISession.Update() with an explicit session which was NOT the session the the package object was instantiated when the list was created (see above) and so the proxy was in fact trying to be associated to two open sessions.

My confusion was caused because NH was trying to help me out and find a proxy for the plan object (a many-to-one) on the package object on the session I was changing and saving, because it was going to save (or see if it needed to) the child first (I guess). I am unsure why cascade="none" did not stop this, perhaps the versioning to see if it needed to do anything with the plan or complain about it if I was trying to prevent it. It threw me off when the problem was first showing itself with the plan and not the package object.

I probably will change my factory object so that if it ever provides an explicit session factory it will refuse to provide a default session factory, which is meant to be used only in the HTTP applications or maybe simple single-threaded solutions. This way, typographical or intellisence-related errors can be caught before they have a domino effect. It anyone else is using a similar pattern, it may help you as well.


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.