NHibernate Pitfalls: Inheritance and Proxies

This is part of a series of posts about NHibernate Pitfalls. See the entire collection here.

If you use inheritance and lazy loading, you may end up with the following situation:

  • You want to access a lazy loaded property of a base class type, of which you don’t know the exact type;
  • You want to do different operations depending on the actual type.

That is usually expressed by this mapping:

   1: public class MyEntity
   2: {
   3:     public virtual SomeBaseClass SomeProperty
   4:     {
   5:         get;
   6:         set;
   7:     }
   8: }
   9:  
  10: public abstract SomeBaseClass
  11: {
  12: }
  13:  
  14: public class SomeConcreteClass : SomeBaseClass
  15: {
  16: }
  17:  
  18: public class AnotherConcreteClass : SomeBaseClass
  19: {
  20: }

And by this code:

The problem is, SomeProperty may not be neither a SomeConcreteClass nor a AnotherConcreteClass. That is because NHibernate creates a proxy for SomeBaseClass
   1: MyEntity e = ...;
   2:  
   3: if (e.SomeProperty is SomeConcreteClass)
   4: {
   5: }
   6: else if (e.SomeProperty is AnotherConcreteClass)
   7: {
   8: }
(read, a derived class), which, because .NET does not support multiple inheritance, cannot also inherit from SomeConcreteClass or AnotherConcreteClass. This property is only loaded upon first access, so, until then, NHibernate has no idea of which class to instantiate, so it will instead create this proxy.

The solution is to use the no-proxy option on the mapping:

   1: mapper.Class<MyEntity>(c =>
   2: {
   3:     c.ManyToOne(x => x.SomeProperty, x =>
   4:     {
   5:         x.Lazy(LazyRelation.NoProxy);
   6:     });
   7: }

This way, NHibernate delays loading of the property, as before, but, instead of returning a proxy to the base class, it will instead return one for the concrete class.

You can find more information on this post by Ayende: http://ayende.com/blog/4378/nhibernate-new-feature-no-proxy-associations.

                             

No Comments