I\'m not an NHibernate user; I write a serialization utility library. A user has logged a feature-request that I should handle NHibernate proxy classes, treating them the sa
If you're writing a generic serialization utility library, I don't think you should handle that specific case at all. Your code should not have a dependency on NHibernate. What you should do is provide hooks that the client code can use to influence the operation of your library.
I'm guessing that you don't really want to access the actual Nhibernate session. This code might better fit your needs:
/// <summary>
/// Returns the real type of the given proxy. If the object is not a proxy, it's normal type is returned.
/// </summary>
internal static Type GetRealType(this object proxy)
{
if (proxy is INHibernateProxy)
{
var lazyInitialiser = ((INHibernateProxy)proxy).HibernateLazyInitializer;
return lazyInitialiser.PersistentClass;
}
else
{
return proxy.GetType();
}
}
Hope that helps.
You can detect if a class is a NHibernate proxy by casting it to (unsurprisingly) INHibernateProxy
.
If you need to get the underlying "real" object, use:
Session.GetSessionImplementation().PersistenceContext.Unproxy(proxiedObject)
You don't need to test for proxies to call Unproxy
; it returns the original parameter if it's not a proxy.
Edit: I now use a different approach to get the underlying object, mostly to work around lazy loading and inheritance: http://sessionfactory.blogspot.com/2010/08/hacking-lazy-loaded-inheritance.html
NHibernate 2.1+ allows the dynamic proxy provider to be set through configuration. The implementations that I'm aware of are Castle (default), LinFu, and Spring. NHibernate does not require an interface or attribute. I think this makes it fairly impossible to reliably detect if an object is a proxy.
As s1mm0t answered, creating the actual type on deserialization is fine.
Diego's method fully loads the object before attempting to determine it's type - this is definitely the most generic approach, but you may not need to load the object if the concrete type is already known to the Proxy.
Vijay's method is faster in cases where the concrete type is known in advance - but as pointed out by Diego, in some cases, that information is not available, because the information required to determine the exact type has not yet been loaded.
Taking both scenarios into account, I came up with the following:
https://gist.github.com/1089489
The interesting piece is this:
if (entity is INHibernateProxy)
{
var lazyInitialiser = ((INHibernateProxy)entity).HibernateLazyInitializer;
var type = lazyInitialiser.PersistentClass;
if (type.IsAbstract || type.GetNestedTypes().Length > 0)
return Service.Session.GetSessionImplementation().PersistenceContext.Unproxy(entity).GetType();
else // we don't need to "unbox" the Proxy-object to get the type
return lazyInitialiser.PersistentClass;
}
return entity.GetType();
This checks first to see if the type behind the Proxy is abstract, and uses Vijay's or Diego's method, depending on whether the concrete type is known.
In other words, it only loads the object if the type behind the Proxy is not a concrete type, or may be of a sub-type.
I did a quick unit test to demonstrate that this works, but I don't imagine I've tested all possible cases - I believe the idea is sound, but I would like to hear comments from Diego and Vijay, or others.
Thanks!
EDIT: Posted an update to the gist above, with an additional generic method that can be used to Unproxy() an Entity - there are some cases where you may have to do that...
There is a tool from NHibernate where you give a type (proxy or not) and it returns the real type. (I am using NHibernate 3)
This is how you use it:
var realType = NHibernate.NHibernateUtil.GetClass(proxyInstance);
Hope this helps :D