Getting proxies of the correct type in NHibernate
I think we recently had a similar problem, AFAIR solution was to give 'Animal' a self -"method/property":
public Animal Self { get { return this; } }
This could then be casted to correct "animal". What happens is that your original object has a reference to nhibernate proxy object (when it's lazily loaded), which acts as Animal for all methods exposed via Animal class (it passes all calls to the loaded object). However it cannot be casted as any of your other animals because it is none of these, it only emulates the Animal class. However the class that is encapsulated by AnimalProxy can be casted as subclassed animal because it is a real instance of correct class, you only need to get to it's this
reference.
It's easiest to turn off lazy loading for the animal class. You say it's mostly in memory anyway.
<class name="Animal" lazy="false">
<!-- ... -->
</class>
As a variant of that, you could also use no-proxy
, see this post:
<property name="OwnedAnimal" lazy="no-proxy"/>
As far as I can see, it only works when the AnimalOwner
actually is a proxy.
OR
You can use generics on the animal owner to make the reference a concrete class.
class AnimalOwner<TAnimal>
{
virtual TAnimal OwnedAnimal {get;set;}
}
class CatOwner : AnimalOwner<Cat>
{
}
class DogOwner : AnimalOwner<Dog>
{
}
OR
You can map the DogOwners
and CatOwners
in separate tables, and define the concrete animal type in the mapping.
<class name="CatOwner">
<!-- ... -->
<property name="OwnedAninal" class="Cat"/>
</class>
<class name="DogOwner">
<!-- ... -->
<property name="OwnedAninal" class="Dog"/>
</class>
OR
You mess a little around with NHibernate, as proposed in this blog. NH is actually able to return the real object behind the proxy. Here a bit simpler implementation as proposed there:
public static T CastEntity<T>(this object entity) where T: class
{
var proxy = entity as INHibernateProxy;
if (proxy != null)
{
return proxy.HibernateLazyInitializer.GetImplementation() as T;
}
else
{
return entity as T;
}
}
which can be used like this:
Dog dog = dogOwner.OwnedAnimal.CastEntity<Dog>();