-->
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.  [ 19 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Serialization and Lazy loaded collections
PostPosted: Mon Jun 12, 2006 10:55 am 
Newbie

Joined: Mon Jun 12, 2006 10:40 am
Posts: 8
Hibernate version:
NHibernate-1.2.0.Alpha1

Mapping documents:

Just a example:

Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  <class
    name="DBA.DomainModel.DomainObjectsImpl.AdNode, DBA.DomainModel.DomainObjectsImpl"
    table="tblAdNode"
    proxy="DBA.DomainModel.DomainObjectsAPI.IAdNode, DBA.DomainModel.DomainObjectsAPI">

    <!-- Keys -->
    <id name="Identity" column="AdNodeId" type="System.Guid" >
      <generator class="guid" />
    </id>

    <!-- Versioning -->
    <timestamp name="Created" />

    <!-- Properties -->
    <property name="ModifiedBy" type="System.Guid"/>
    <property name="CreatedBy" type="System.Guid"/>

    <!-- Relations-->
    <bag name="Children" lazy="true" inverse="true" cascade="all">
      <key column="Parent" />
      <one-to-many class="DBA.DomainModel.DomainObjectsImpl.AdNode, DBA.DomainModel.DomainObjectsImpl"  />
    </bag>

    <many-to-one
        name="Parent"
        cascade="all"
        class="DBA.DomainModel.DomainObjectsImpl.AdNode, DBA.DomainModel.DomainObjectsImpl" />
  </class>
</hibernate-mapping>


I'm currently trying to use ASP.NET 2.0's http-session in conjunction with lazy loaded collections.

I've read elsewhere on this board that if you want to serialize, you should'nt use lazy-loading. But in this case we simply have to lazy-load - if we don't we'll almost load the entire database per-page request.

So when I add the objects to the session, it also seems to add the proxy-stubs without any problems - is there any way to hook up those stubs again (on deserialization)?

And if there is, can the hook-up be automatic? So I don't have to know what collections to hook up on my parent object, but just calls some function with the parent.

I would like to avoid going down the reflection-road, but I'm guessing that could be a way - iterating over any collections and hooking them up one by one.

It should be noted, that the objects that I serialize does not come from nhibernate - they just have references to objects that do.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 12, 2006 12:38 pm 
Newbie

Joined: Mon May 22, 2006 12:22 pm
Posts: 12
Basically you want to intialize the items you'll need before the http request has ended.

Check out the implementation by Billy McCafferty

http://www.codeproject.com/aspnet/NHibe ... ctices.asp


Top
 Profile  
 
 Post subject: Does it solve my problem?
PostPosted: Tue Jun 13, 2006 3:50 am 
Newbie

Joined: Mon Jun 12, 2006 10:40 am
Posts: 8
Thanks a lot for your feedback.

I've studied both the code and the article, and it does provide some very nice things (eg. session mangement).

But I don't see how it solves my problem.

It does make lazy-loading easier and everything - but I'll still get the proxy references in the objects I add to asp.net-session.

Even if I force those proxies to load their content, they in-turn may have yet more references to lazy content - I would never know here to stop?

Thanks in advance.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 13, 2006 10:57 am 
Expert
Expert

Joined: Fri May 13, 2005 5:56 pm
Posts: 308
Location: Santa Barbara, California, USA
Quote:
Even if I force those proxies to load their content, they in-turn may have yet more references to lazy content - I would never know here to stop?


in this case, you are running into some design theory in Hibernate. basically, your collections are maps that should be used in HQL queries that populate the object graph for each specific situation. in some cases you might need Parent.Children. In other cases you might need Parent.Children.ChildrenOfChildren.

the recommendation by the Hibernate team is to form specific queries in your DAO that load these twoobject graphs and call those queries when you need them instead of initializing a lazily-loaded collection. i hope i'm making sense here but another way to say it is that your DAO should have specific HQL queries that load the object graph (and depth) that you need for a specific instance.

-devon


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 13, 2006 1:32 pm 
Pro
Pro

Joined: Fri Nov 19, 2004 5:52 pm
Posts: 232
Location: Chicago, IL
Just so I understand, what you are doing is doing an NHibernate query in one request, storing the results in ASP.NET's session state, then attempting to access lazy loaded collections in a subsequent request?

Have you tried reattaching the object graph using ISession.Lock()?


Top
 Profile  
 
 Post subject: Reattaching the object graph
PostPosted: Wed Jun 14, 2006 6:58 am 
Newbie

Joined: Mon Jun 12, 2006 10:40 am
Posts: 8
Yes, I have tried that - and it also seems like one possible solution.

The probelem is - I don't know how far to go in the graph to reconnect. I have quite a deep graph of new objects (3-4 types) and for each level I have references to lazy-loaded objects/collections.

- I would have to write code that loops through all that and calls lock - and if I change anything (like a single collection to any class in the hieracky) I have to rewrite that code.

I could see how this also could be done by using reflection - but what about performance. Writing code for that could prove difficult.

---

And devonl, yes you do make sense - and it may be an easier solution ... but a bit less oo-like - would be nice to be able to do a object.child.child.child.child..... and so on.

The other way around, I have to think a lot more - and do a lot more checks against the dal-layer (and less checks against the domainmodel)


Last edited by modec on Wed Jun 14, 2006 10:21 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Reattaching the object graph
PostPosted: Wed Jun 14, 2006 7:00 am 
Newbie

Joined: Mon Jun 12, 2006 10:40 am
Posts: 8
Ups, double post - deleted


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 14, 2006 12:22 pm 
Pro
Pro

Joined: Fri Nov 19, 2004 5:52 pm
Posts: 232
Location: Chicago, IL
As far as I know, all you should have to do is reattach the root object using ISession.Lock() (and NHibernate takes care of the all the objects that it references). You don't have to do it for child objects. I haven't yet used Lock() myself, but, I've used SaveOrUpdate() without problems.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 16, 2006 7:04 am 
Newbie

Joined: Mon Jun 12, 2006 10:40 am
Posts: 8
Hm. it doesent seem to reconnect the whole graph, unless it's casade all. But I think I can write the code using reflection ...


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 16, 2006 7:08 am 
Newbie

Joined: Mon Jun 12, 2006 10:40 am
Posts: 8
Ok - I also seem to have a problem with those cases where I haven't got a lazy loaded collection. And ISession.Lock gives me the following exception:

An exception of type 'System.InvalidCastException' occurred in NHibernate.DLL but was not handled in user code

Additional information: Unable to cast object of type 'NHibernate.Collection.Generic.PersistentGenericBag`1[DBA.DomainModel.DomainObjectsAPI.IAdNode]' to type 'NHibernate.Proxy.INHibernateProxy'.

So I guess the question is ... How do I reconnect if the collections aren't of type proxy?

I hate having to handle all this on serialization/deserialization - is the any better practicies when using NHibernate?

Basically I just wanna keep a keep a object-graph in memory (with references to persisted objects) without doing a lot of work....


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 16, 2006 8:05 am 
Senior
Senior

Joined: Sat Mar 25, 2006 9:16 am
Posts: 150
Please post a follow-up when you have found the best resolution... I have the same issues and it seems many others do as well.

There seems to be something missing from the design perspective of how to use NH. Yes, you can specify the relationships of your whole database in mapping files. But there is no clean way to specify which objects in the graph to load on any given call. All the solutions I have seen have drawbacks:

1. Lazy load everything - does not work when objects are serialized across a service, or in any tiered architecture where the data layer must close the connection before returning to the caller

2. Don't use the criteria API. Use HQL for everything - thus defeating the purpose of even having a criteria API

3. Define different entities which map to the same tables but with different relationships - hack city

4. Explicity load (with NHibernateUtil.Initialize) or null out related objects - requires enumerating through the entire object graph (as discussed above) - fragile and bug-ridden


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 16, 2006 8:26 am 
Newbie

Joined: Mon Jun 12, 2006 10:40 am
Posts: 8
Don't worry grennis, I will.

I've actually gotten a bit further. It seems to work a little better if I force the collections to be loaded before I throw them into session - eg. by doing a.
int i = collection.count;

-

But then I've sacrificed lazy-loading. And I still have to do this on all collections at all levels...


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 16, 2006 8:48 am 
Senior
Senior

Joined: Thu Aug 25, 2005 3:35 am
Posts: 160
So, you haven't gotten any further, according to the things Grennis is worried about.

I would agree there is something missing in the design of nH when you want to use it in tiered applications.
I would suggest using the serialization and deserialization hooks when crossing tiers, to find out if something is initialized or not.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 16, 2006 9:09 am 
Senior
Senior

Joined: Sat Mar 25, 2006 9:16 am
Posts: 150
modec wrote:
I force the collections to be loaded before I throw them into session - eg. by doing a.
int i = collection.count;


I think the official way to do this NHibernateUtil.Initialize(parent.ChildCollection)


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 16, 2006 11:57 am 
Newbie

Joined: Mon May 22, 2006 12:22 pm
Posts: 12
modec that's my hack at the moment as well, even though the item does get initialized, it still doesn't get passed across the wire for some reason. this is obviously not the optimal solution as my collections may contain objects that have collections themselves. so i'm still in need of a better solution


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 19 posts ]  Go to page 1, 2  Next

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.