For some time I have put off implementing lazy-loading in my current project because (ironically) I am lazy. it is just conceptually easier to load the object you want and then move on. I think this due to a brief encounter I had with a NHibernate-created frankenproxy when I issued a' ToString () 'On one of the objects I had loaded and as far as I recollect I got the crazy proxy name instead of Override ToString () value I expected. now I am sure now I had simply not overriden ToString () like I thought I had but I simply haven' t had time to sit down and design as if my objects were lazy loaded. the notes here are what I picked up today so if you see something wrong please let me know!
The proxied instances returned by NHibernate will invoke the ToString (), Equals (), and GetHashCode () methods to the target object type if they have been overriden (which I hope is the case ). this might be a concern since the proxies themselves wocould have these methods, but they are transparent in this regard.
The newer versions of nhib1_load lazily by default, so it is important to have made decisions and understand what your Unit of Work strategy is. assuming this is an ASP. NET application, are you storing your ISession in the Context. items and having the end of the Request flush your ISession? (A common practice) this is relevant because it is important to know that if you are working with objects that have been loaded lazily after the session has been flushed will throw an NHibernate exception since the proxy can't invoke its target without an ISession. if this comes up, you may reattach the object to the current ISession using session. lock (myObject ). personally, I use FlushMode. commit mode since I like things to happen when I instruct them to and it is conceptually easier for me than to tie my. flush () to an event.
There are a couple of options for determining the objects NHibernate will return from its lazy-loads.
#1
The most common is to simply mark the class with the 'Lazy = "true" 'attribute or place 'default-lazy = "true" 'in the mapping declaration:
<Hibernate-mapping xmlns = "urn: nhibernate-mapping-2.2" assembly = "@ core. assembly @"
Default-access = "nosetter. camelcase-underscore" default-lazy = "true">
Or
<Class name = "Cei. eMerge. Core. Domain. Contacts. Contact" table = "Contact" lazy = "true">
If you go this route, remember the following:
- Have a default constructor that is at leastProtected Visibility.PrivateWill not be able to be proxied.
- Properties and methods will need to be markedVirtual. This is because the proxy returned by NHibernate isSubclassOf your object. this point might make you hesitate to go the lazy-loading route, but don't let it. the DDD purist might shudder because the persistence mechanic is somehow influencing the domain objects (of course the default constructor NHibernate requires is another violation of this ). this is one of those decisions where your business objectives need to drive your demo-instead of your technology objectives... it might make sense to avoid this, but be sure you weweigh the performance benefit of lazy-loading in there, too.
- This route allows you to useFieldAccess strategy for things like read-only collections and so on. I explain this in the next section.
#2
The other option is to tell NHibernate whatInterfaceTo return for your proxy using the 'proxy = "IMyInterface" 'in the class declaration:
<Class name = "Cei. eMerge. Core. Domain. Contacts. Contact" table = "Contact" proxy = "IContact">
Remember this is you go this route:
Properties and methodsDon'tNeed to be markedVirtual.
- This will impact the access strategies available to your objects 'members. if you were to use 'Access = "field. camelcase-underscore "'or' access =" nosetter. camelcase-underscore "'for one of the properties above Nhibernate will try to find a member such a name as" _ fieldName "and will throw an exception because thatDoesn' t exist in your interface. One solution wocould be to change the access strategy to "access =" property "(the default) and allow for an setter that has a "lower" visibility (C #2.0 and higher only ). that way, the visiblity is still restricted but NHibernate can set your properties 'values. but wait... here again we are letting persistence decisions trickle into our domain objects. that may be fine, but it shoshould still be a deliberate demo. for example, onPersonImplementationIPersonWe might have:
/// <Summary>
/// The First Text of an Individual Contact. Such as "Franz" or "Harry ".
/// </Summary>
Public virtual string FirstName
{
Get
{
Return _ firstName;
}
Protected set {_ firstName = value ;}
}
- A final common issue is casting. if you lazyload an object and try to cast it to its inherited type, you will get a cast exception. remember you are dealing with a proxied instance which is a subclass of your intended object... thus the casting exception.
The benefits of lazy-loading can be immense. Not only can you avoid the commonSelect n + 1Problem, but you can drastically reduce the size of the queries hitting your db. this will especially be important if you have, say, turned ViewState off and are hitting the DB for data with each request and caching isn' t an option.
UPDATE: I goofed when I wrote this (late at night ). select N + 1 is something to beware of when dealing with lazy loading. see this post by Oren Eini for ways to deal with this. thanks Bill for catching my error!