Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,125 | Comments: 45,488

filter by tags archive

NHibernate new featureNo proxy associations

time to read 3 min | 401 words

About three weeks ago I introduced the problem of ghost objects in NHibernate. In short, given the following model:


This code will not produce the expected result:

var comment = s.Get<Comment>(8454);
if(comment.Post is Article)

You can check the actual post for the details, it related to proxying and when NHibernate decides to load a lazy loaded instance. In short, however, comment.Post is a lazy loaded object, and NHibernate, at this point in time, has no idea what it is. But since it must return something, it returns a proxy of Post, which will load the actual instance when needed. That leads to some problems when you want to down cast the value.

Well, I got fed up with explaining about this and set about to fix the issue. NHibernate now contains the following option:

<many-to-one name="Post" lazy="no-proxy"/>

When lazy is set to no-proxy, the following things happen:

  • The association is still lazy loaded (note that in older versions of NHibernate, setting it to no-proxy would trigger eager loading, this is no longer the case).
  • The first time that you access the property the value will be loaded from the database, and the actual type will be returned.

In short, this should completely resolve the issue.

However, not the key phrase here, like lazy properties, this work by intercepting the property load, so if you want to take advantage of this feature you should use the property to access the value.

More posts in "NHibernate new feature" series:

  1. (28 Jan 2010) No proxy associations
  2. (27 Jan 2010) Lazy Properties


Tyler Burd

This is great! I know that it violates Liskov and such, but so many new/junior programmers get bitten by this when they first introduce inheritance in their model.

Cassio Tavares

Really Great, but do you recommend use it in all many-to-one associations? Is there a rule?

Steve Degosserie

Why not load the type of the associated object during the initial query (might need to add some joins depending on the inheritance storage strategy chosen) so that a proxy of the correct type can be generated ?

Ayende Rahien

No, I don't.

If you can, keep the current behavior. This requires NH to do more work and it encourage bad design practices

Ayende Rahien


You can do that if you want to eager load.

But in some cases, you want to do things lazily.

Steve Degosserie

I mean, NH could automatically pre-load to the entity type of lazy many-to-one association.

If I do a comparison 'comment.Post.Id == 123', you know it better than me, Post is not going to be lazy-loaded because the proxy holds the Id. Similarly, I would expect lazy-loading not to be triggered if I do 'comment.Post is Article'.

Ayende Rahien


That implies eager loading, the same cost is associated with this or with eager loading.


Just out of curiosity (I'm not a NHibernate-user). The Comment.Post-property has to be virtual in order to allow this behaviour, right?

Ayende Rahien


In general, all properties/methods must be virtual.

Martin Aatmaa

To rephrase Cassio Tavares' question:

Do you recommend to use it in all many-to-one polymorphic associations?

Ayende Rahien


Again, no. Use it if you need it, but I don't like needing it

Ayende Rahien


I still don't agree with your reasoning.

And it takes a single query.

Alex Yakunin

Ah, yes... Surely there is a single query when yo materialize a proxy. But what happens if you access a property of inherited type later?

Concerning the reasoning - well, deeds say more than words.

Alex Yakunin

when yo materialize a proxy

Sorry, wrong description, I mean "when NH resolves the reference".

Ayende Rahien


If you access the property, there is no query.

re: deeds, there are things that I do because people want it enough, not because I think it is good

Alex Yakunin

there are things that I do because people want it enough, not because I think it is good

Good answer ;)

If you access the property, there is no query.

So may be I'm missing something. While doing the first query, you actually don't know the exact type of referenced entity (of course, if there is inheritance hierarchy with type discriminator), and thus you don't know how to completely fetch the instance.

Querying all the tables from the hierarchy is, likely, a bad idea as well, because there can be lots of them.

So how such case is handled?

Ayende Rahien

When you access the property on the root entity, we load the value (one query).

Alex Yakunin

Let's imagine we have Person.Pet reference of Animal type, and the instance it refers can actually be of type Cat, Dog, ... any other of its 20 inheritors (so the hierarchy is mapped to 20 different tables). And we use class per table inheritance mapping with type discriminator.

Let's think I run the following code:

var person = ...; // Person instance is loaded

var pet = person.Pet; // Animal instance is loaded, but in which part?

var dog = pet as Dog;

if (dog!=null) {

double barkVolume = dog.BarkVolume; // Any DB interaction?


Ayende Rahien


var person - db query

person.Pet - db query.

That is all


Nice! just a question: all these new proxy/lazy loafing new features are here because hibernate has them or just because they are really good? The proper question should be: is nhibernate still following hibernate's steps?

Ayende Rahien


NHibernate still follows in Hibernate footsteps, but is not limited to them

Alex Yakunin

person.Pet - db query

Which tables will be used by this query in described case?

Ayende Rahien


Similar to what would happen if I did:


Alex Yakunin

If I understand everything correctly, earlier session.GetPet would return a proxy, which type isn't dependent on actual Pet type there (i.e. won't be able to successfully cast it to e.g. Dog).

The query that would run in this case fetches just Dog's fields, so this line must lead either to DB interaction, or to unexpected result:

double barkVolume = dog.BarkVolume; // Any DB interaction?

But since you describe new functionality, it's desirable to describe what's changed in this case.

Alex Yakunin

(i.e. won't be able to successfully cast it to e.g. Dog).

I mean "I won't be able to ..."

The query that would run in this case fetches just Dog's fields

Sorry, "Pet's fields."

Ayende Rahien


Get does NOT return a proxy.

Alex Yakunin

Now it's clear that your statement about session.Get was correct. I tried to find out what actually NHibernate does to load an instance mapped with "joined-subclass" strategy, and actually failed. I see two basic options here:

a) Do this using a single query involving all the tables in the hierarchy ( or b) a part of them, if entity type is partially known - e.g. as T generic argument of session.Get method)

c) Query for hierarchy root type, detect actual entity type and run a precise query involving just necessary tables.

So what algorithm is used by NHibernate in this case? A, b, c, a combination of some of them, etc.?

Alex Yakunin

Thanks for a link - there is really a perfect example.

So just to confirm: does NHibernate always use way a) ?

Ayende Rahien


To perform polymorphic query, yes

Alex Yakunin

Ok, thanks. Thinking on consequences...

Comment preview

Comments have been closed on this topic.


  1. The design of RavenDB 4.0: Physically segregating collections - 6 hours from now
  2. RavenDB 3.5 Whirlwind tour: I need to be free to explore my data - about one day from now
  3. RavenDB 3.5 whirl wind tour: I'll have the 3+1 goodies to go, please - 4 days from now
  4. The design of RavenDB 4.0: Voron has a one track mind - 5 days from now
  5. RavenDB 3.5 whirl wind tour: Digging deep into the internals - 6 days from now

And 12 more posts are pending...

There are posts all the way to May 30, 2016


  1. The design of RavenDB 4.0 (14):
    03 May 2016 - Making Lucene reliable
  2. RavenDB 3.5 whirl wind tour (14):
    04 May 2016 - I’ll find who is taking my I/O bandwidth and they SHALL pay
  3. Tasks for the new comer (2):
    15 Apr 2016 - Quartz.NET with RavenDB
  4. Code through the looking glass (5):
    18 Mar 2016 - And a linear search to rule them
  5. Find the bug (8):
    29 Feb 2016 - When you can't rely on your own identity
View all series


Main feed Feed Stats
Comments feed   Comments Feed Stats