Request for help refactoring code for which NHibernate lazy initialization is broken

34 views
Skip to first unread message

Kenny Evitt

unread,
Jul 25, 2013, 3:58:43 PM7/25/13
to sharp-arc...@googlegroups.com
I've inherited an application that's using S#arp Architecture (2.0.4 according to the NuGet package installed).

Before starting work on this application, I was very inexperienced with NHibernate and unfamiliar with S#arp Architecture.

I suspect the application isn't really following the spirit of S#arp Architecture or NHibernate applications. Here's a (somewhat simplified) example of said improperly-spirited code:

                var parentEntityX = NHibernateSession.CurrentFor(SessionKeys.Db1).QueryOver<ParentEntity>()
                    .Where(x => x.Id == parentEntityId)
                    .SingleOrDefault<ParentEntity>();
                ...
                someViewModelVariable = _someQueryClass.GetChildEntity(parentEntityX)

and then the code for the method GetChildEntity(ParentEntity parent):

                return new SomeViewModelClass {
                 Id = parent.Child.Id,
                 GrandchildName = parent.Child.Grandchild.Name
                }

The expression parent.Child.Grandchild.Name raises an exception of type NHibernate.LazyInitializationException, which, after a few hours Googling, kinda makes sense. Whatever NHibernate (and maybe S#arp Architecture) are doing to keep track of the session, it certainly wouldn't be obvious to me that the GetChildEntity method code would be able to access the same session as used in the calling code.

But nearly all of the data code uses the NHibernateSession.CurrentFor(SessionKeys.Db1).QueryOver<ParentEntity>()... idiom and that doesn't seem to be working. An even worse example, at least in my mind and given my current understanding, is that some view model classes contain member properties with types of various entity classes. I've run into the same lazy-initialization exception issue with view code using those view model classes.

Should I just rewrite the code? The entire application? Or is there some less drastic way to replace the basic pattern I've described above with something that avoids the problems I've identified?

Simone Busoli

unread,
Jul 25, 2013, 4:12:59 PM7/25/13
to sharp-architecture

It very much depends on when GetChildEntity is called exactly, which you didn't explain. Having model classes in the viewmodel can indeed be a problem, in that case session lifetime issues will most likely arise, though not in the example you provided.

--
You received this message because you are subscribed to the Google Groups "S#arp Architecture" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sharp-architect...@googlegroups.com.
To post to this group, send email to sharp-arc...@googlegroups.com.
Visit this group at http://groups.google.com/group/sharp-architecture.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Carl Bussema

unread,
Jul 25, 2013, 4:43:30 PM7/25/13
to sharp-arc...@googlegroups.com
If you just do something simple a test, retrieve one object of parentEntityX, then attempt to access its .Child.Grandchild.Name property, does it throw the exception? Back each of those off a level... try accessing just .Child for instance, and see if the LazyInitializationException persists. I'm not sure what the problem here would necessarily be, except possibly that you're trying to lazy-load two levels at once. 

You could also try changing your mappings to remove lazy loading, depending on whether that's practical for performance.

Kenny Evitt

unread,
Jul 26, 2013, 10:20:42 AM7/26/13
to sharp-arc...@googlegroups.com
The example block of code was adapted from the actual code and is contained in a single method (in a controller class). The "...", in the actual code, is another method call that makes a call like "NHibernateSession.CurrentFor(SessionKeys.Db1).GetNamedQuery("SomeQuery")..." (and attempts to populate a list of 'DTO' objects).
To unsubscribe from this group and stop receiving emails from it, send an email to sharp-architecture+unsub...@googlegroups.com.

Kenny Evitt

unread,
Jul 26, 2013, 10:42:04 AM7/26/13
to sharp-arc...@googlegroups.com
I just stepped thru the code and attempting to access the .Child.Grandchild.Name property immediately the 'parentEntityX' object is loaded does NOT throw the exception. As I wrote in reply to SimoneB [awaiting approval], the code corresponding to the "..." calls a method that attempts to load a list of 'DTO' objects from a named query – attempting to access the .Child.Grandchild.Name property after that method is run ...

I think your questions (and SimoneB's as well) have suggested enough for me to understand what's wrong. My last reply wasn't entirely true – there were several method calls, all accessing data, but the offending code I now believe is this statement:

NHibernateSession.CurrentFor(SessionKeys.RecapDbSql2).Clear();

I have no idea why the session is being cleared, but I can understand (better) now why it would be a problem! I'm more surprised that the code seemed to even partially work at all now.


On Thursday, July 25, 2013 4:43:30 PM UTC-4, Carl B wrote:
If you just do something simple a test, retrieve one object of parentEntityX, then attempt to access its .Child.Grandchild.Name property, does it throw the exception? Back each of those off a level... try accessing just .Child for instance, and see if the LazyInitializationException persists. I'm not sure what the problem here would necessarily be, except possibly that you're trying to lazy-load two levels at once. 

You could also try changing your mappings to remove lazy loading, depending on whether that's practical for performance.
On Thu, Jul 25, 2013 at 4:12 PM, Simone Busoli <simone...@gmail.com> wrote:

It very much depends on when GetChildEntity is called exactly, which you didn't explain. Having model classes in the viewmodel can indeed be a problem, in that case session lifetime issues will most likely arise, though not in the example you provided.

On Jul 25, 2013 9:05 PM, "Kenny Evitt" <kenny...@gmail.com> wrote:
I've inherited an application that's using S#arp Architecture (2.0.4 according to the NuGet package installed).

Before starting work on this application, I was very inexperienced with NHibernate and unfamiliar with S#arp Architecture.

I suspect the application isn't really following the spirit of S#arp Architecture or NHibernate applications. Here's a (somewhat simplified) example of said improperly-spirited code:

                var parentEntityX = NHibernateSession.CurrentFor(SessionKeys.Db1).QueryOver<ParentEntity>()
                    .Where(x => x.Id == parentEntityId)
                    .SingleOrDefault<ParentEntity>();
                ...
                someViewModelVariable = _someQueryClass.GetChildEntity(parentEntityX)

and then the code for the method GetChildEntity(ParentEntity parent):

                return new SomeViewModelClass {
                 Id = parent.Child.Id,
                 GrandchildName = parent.Child.Grandchild.Name
                }

The expression parent.Child.Grandchild.Name raises an exception of type NHibernate.LazyInitializationException, which, after a few hours Googling, kinda makes sense. Whatever NHibernate (and maybe S#arp Architecture) are doing to keep track of the session, it certainly wouldn't be obvious to me that the GetChildEntity method code would be able to access the same session as used in the calling code.

But nearly all of the data code uses the NHibernateSession.CurrentFor(SessionKeys.Db1).QueryOver<ParentEntity>()... idiom and that doesn't seem to be working. An even worse example, at least in my mind and given my current understanding, is that some view model classes contain member properties with types of various entity classes. I've run into the same lazy-initialization exception issue with view code using those view model classes.

Should I just rewrite the code? The entire application? Or is there some less drastic way to replace the basic pattern I've described above with something that avoids the problems I've identified?

--
You received this message because you are subscribed to the Google Groups "S#arp Architecture" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sharp-architecture+unsub...@googlegroups.com.

To post to this group, send email to sharp-arc...@googlegroups.com.
Visit this group at http://groups.google.com/group/sharp-architecture.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

--
You received this message because you are subscribed to the Google Groups "S#arp Architecture" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sharp-architecture+unsub...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages