Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NHibernate - access the ID of an associated object without lazy loading the whole object

I have two associated business objects - A and B. the association is (A->B)many-to-one, with B.Id a foreign key in A (so A has A.B_id in the DB).

I'm using lazy=true and solved most of my problems, however in A's ToString I want to print also A.B.Id, which I should have without further trips to the DB. but accessing A.B activates the proxy, and since this isn't in the context of an open session, throws an exception.

one easy but ugly solution would be to have A.B_id property. but that's part of the stuff we were trying to avoid in the first place. any "organic" way to do this? :) thanks!


UPDATE: just read about caching and Session.Get vs. Session.Load. before I only new that one throws an exception if the object doesn't exist (Session.Load), and the other returns a null object (Session.Get). after reading about caching here, it's clear that Session.Load returns a proxy to the object, and only lazily fetches it when a property other than the ID is accessed, which is very much like what I need from associations! for now I added the separate object ids (added B_Id to A so I can access it as A.B_Id instead of using A.B.Id)

like image 208
Yonatan Karni Avatar asked Nov 09 '09 16:11

Yonatan Karni


2 Answers

If you are using NHibernate 3.2 or later, you could use the following code to get the id of associated object without another roundtrip to database to load the whole object:

using NHibernate.Proxy;
...
object id = null;
if (obj.IsProxy()) // obj is the object you want to get its identifier.
{
    var proxy = obj as INHibernateProxy;
    if (proxy != null)
    {
        var li = proxy.HibernateLazyInitializer;
        if (li != null) 
            id = li.Identifier;
    }
}
like image 73
Quan Avatar answered Oct 29 '22 18:10

Quan


For the exact same reason I have used explicit A.B-ID properties for all my many-to-one relationships. I do not see this as a quick and dirty solution as it provides a solution to this problem and also lot of flexibility is the saving-updating area i.e. I do not need to fetch from the database the B object just to assign it to A in order to create the association when I have the B_ID in a query string or somewhere else.

My mapping files useually look like this:

<property name="CreatorID" column="CreatorID" type="Int32" not-null="true" />
<many-to-one name="Creator" column="CreatorID" class="SystemUser" insert="false" update="false" cascade="none" />

As you can see one of the 2 properties has to be read only to avoid having NHibernate sending 2 times this column to the database when inserts or updatas are happening. The above makes as read only (by using the insert="false" update="false" attributes) the many-to-one but you can instead have as read only the CreatorID property if you like.

Having only the many-to-one you do not have a property in your entity class A to hold the B.ID value. The only way to get it is by accessing the B object which will trigger the proxy and it will fire a query to the database (if it is not loaded in the session already).

I will be happy to hear any other option that provides a solution and offers the same kind of flexibility.

like image 5
tolism7 Avatar answered Oct 29 '22 19:10

tolism7