-->
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.  [ 8 posts ] 
Author Message
 Post subject: Problem with cache-db sync
PostPosted: Sat Oct 06, 2007 3:30 am 
Newbie

Joined: Sat Oct 06, 2007 3:16 am
Posts: 3
Hello. I'm learning NHibernate and I have the following trouble:
I want to map a tree, so I've created the following xml-file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="test1" assembly="test1">
<class name="MyClass" table="MyTable">
<id name="MyID" column="ID">
<generator class="native" />
</id>
<many-to-one name="Parent" class="MyClass" column="ParentID" fetch="join" />
<set name="Children">
<key column="ParentID" />
<one-to-many class="MyClass" />
</set>
</class>
</hibernate-mapping>

but the following code returns(writes to console) 0:

MyClass Root = new MyClass();
Root.Parent = null;
session.Save(Root);
int RootID = Root.MyID;

MyClass Child = new MyClass();
Child.Parent = Root;
session.Save(Child);
session.Flush();
//session.Clear()
Root = (MyClass)session.Get(typeof(MyClass), RootID);

Console.Out.WriteLine("Cache: Root.Children.Count = " + Root.Children.Count);

Uncommenting 'session.Clear()' results in correct answer(1)
So, the question is 'How to get cache synced with DB' without 'session.Clear()?'

Sorry for my bad English.

Thanks


Top
 Profile  
 
 Post subject:
PostPosted: Sat Oct 06, 2007 10:01 am 
Hibernate Team
Hibernate Team

Joined: Tue Jun 13, 2006 11:29 pm
Posts: 315
Location: Calgary, Alberta, Canada
Without calling Root.Children.Add(Child), Child would not get added to the Root.Children collection. With the exception of when the entity is loaded, NHibernate does not do anything automatically; you as the programmer are responsible for ensuring that the in-memory object associations are correct. In this case, setting Child.Parent but not add Child to the Root.Children violate that.

Now the direct answer to your question is that you may call session.Refresh(Root) to reload the state from the database. Having said that, Refresh() is typically used only to sync up with the database only when there are externally-triggered things to be synced up -- such as a timestamp field or effects of triggers. Synching up a relationship as in the example/test you have given is not typical usage and it is discouraged.

_________________
Karl Chu


Top
 Profile  
 
 Post subject:
PostPosted: Sat Oct 06, 2007 11:22 am 
Newbie

Joined: Sat Oct 06, 2007 3:16 am
Posts: 3
Nice answer, thank you. But then I've got another question:
I don't want to write Root.Children.Add and .Parent = Root everytime I add an instance to a tree. Of course I can set .Parent as a property and change .Children when .Parent changes. But can I handle ISet.Add somehow(without creating proxy class)?
Or even ask NHibernate to do that work with one-to-many association?


Top
 Profile  
 
 Post subject:
PostPosted: Sat Oct 06, 2007 12:39 pm 
Hibernate Team
Hibernate Team

Joined: Tue Jun 13, 2006 11:29 pm
Posts: 315
Location: Calgary, Alberta, Canada
A typical approach is to hide the real collection and provide AddChild(...) and RemoveChild(...) methods. In those methods, you handle the association and make sure that things are set up correctly in both directions. If you need access to the whole Children collection (for binding to a grid, for example), create a method called GetChildren() and return a copy of the collection. The objective is to clamp down on how one can interact with the collection outside of the Root class.

_________________
Karl Chu


Top
 Profile  
 
 Post subject:
PostPosted: Sat Oct 06, 2007 2:25 pm 
Newbie

Joined: Sat Oct 06, 2007 3:16 am
Posts: 3
I see. Thank you.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 07, 2007 6:32 am 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
Using the method described above for wrapping collections the main collection is never exposed. Presumably that then prevents you from being able to use the ISession.CreateFilter methods to filter the contents of a child collection.

Does anyone have a better solution? I remember Ayende's solution to the problem in his NHibernate.Generics seemed fairly elegant even if it did "encourage" people to add logic in the delegates that handled the collection wiring.

The new "best practice" just seems to cripple things a bit too much for my liking. Or have I missed something?

Symon.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 07, 2007 6:57 am 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
Of course if you need to be able to filter the collection and don't mind everybody else getting access to the collection instance, then just make the collection getter public and that's all.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 07, 2007 7:41 am 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
Of course, that then defeats the possibility of controlling access to the collection using the AddChild and RemoveChild methods. Maybe it would be possible to use a generic UserCollection that could use delegates to manage the relationships?

Symon.


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