An interesting issue was brought up on the S#arp Architecture discussion today (it was actually brought up on the old S#arp forum...but then I couldn't plug the new location! ;). If you use System.Web.Mvc.BindingHelperExtensions.UpdateFrom to copy
fields from a submitted ASP.NET MVC form into an object loaded using NHibernate's Session.Load() method, no data may be copied to the object.
Mark, the person who brought up the issue, noticed in the debugger that the object being updated was actually a proxy using
Castle.Core.Interceptor.IInterceptor. The reason that this is occurring is that, by default, NHibernate
lazily loads objects. For example, assume you load a Customer from the
DB using Session.Load(); NHibernate won't take the time to talk to the database and set the object's properties until one of the object's properties or methods are invoked on the myCustomer object.
To make this magic trick work, NHibernate gives you a proxy
object that informs NHibernate when it's time to actually hit the
database; NHibernate uses the Castle Proxy project
to facilitate proxying. Since UpdateFrom uses reflection to update the object's values,
it won't kick off the proxy's "time to talk to the database and load
the real object" trigger.
You have three options to work around this limitation of UpdateFrom trying to update the proxy object:
- Add lazy="false" to the opening class tag within the object's HBM
file. This will ensure that the object is not loaded lazily and will
not give you an intermediary proxy.
- Load the object from the database using NHibernate's Session.Get()
method. This method will never return a proxied object. (This replaced NHibernate's deprecated Find() method.)
- Look
at one of the properties or invoke a method on the object before your
call to UpdateFrom. This will force NHibernate to replace the proxy
with the actual object loaded from the database. (Albeit, not a very elegant
solution.)
The first and second options are the cleanest approaches and, as a nice
side-effect, you won't have to add "virtual" before that object's
properties and methods if you set lazy="false" in the class declaration.
Related references:
Billy McCafferty