Oh yeah, I have a blog; maybe I should post something once in a while.

The Problem...

So, at work I finally had an opportunity to use NHibernate on a little project. This project is a very simple data retrieval service. The service will only ever read from the data store; it will never write to it. Because of the sensitive nature of the data, we are required to use views that were built specifically for our project. The views do not contain any unique identifiers. Below is an example of a details view we would have. This details view contains personal information about a person; their name, phone number, address, etc. We also have an identifier for each person; however, the identifier is not unique in the view. The person can be listed multiple times for each year they are registered.

The problem started when I used NHibernate to pull back records for a person who was registered more than 1 year. Below is the result set I expected back from NHibernate:

Identifier FirstName LastName PhoneNumber RegisteredYear
12345 Mary Smith 555-1234 2007
12345 Mary Jones 555-5678 2008
12345 Sara Jones 555-5678 2009

But what I actually get back from NHibernate is 3 Person objects, all with duplicate data like so:

Identifier FirstName LastName PhoneNumber RegisteredYear
12345 Mary Smith 555-1234 2007
12345 Mary Smith 555-1234 2007
12345 Mary Smith 555-1234 2007

When I discovered this, my first thought was that NHibernate is doing some sort of caching under the hood.  Then, for some reason, because the person identifier matches on the next results, it just returns a list of the same object multiple times. So, being VERY new to NHibernate, I googled about turning caching off.  I found a thread mentioning to use an IStatelessSession instead of an ISession.  I did that; didn't fix it. Below is an example of the (very simple) HQL query that I'm doing (yes it's VB, another requirement of this project).

Dim session As IStatelessSession = NHibernateHelper.OpenStatelessSession()
Return session.CreateQuery("from Person p where p.Identifier = :id") _
              .SetString("id", identifier).List(Of Person)()

Again, I am certainly an NHibernate n00b. I'm starting to really love the tool, but I am learning that there is a bit of a learning curve when it comes to the more advanced features. So at this point I was quite stumped. Google was now failing me, and I was starting to think about scraping NHibernate and just doing straight ADO. As a last ditch effort, I reached out to a circle of developers that have much more experience with this fantastic ORM.

I got good tips from a few guys, which helped me learn a bit of what NHibernate is doing, but they still weren't fixing my problem. One of the suggestions was telling me I had cartesian products in a non lazy collection.  However, this couldn't be the case as I did not have any collections in these objects.  None of the views that we were accessing reference any other views or tables so there are no joins being built by NHibernate.  Finally, I received a response from James Kovacs who explained the problem quite well:

"As far as I can tell, the problem isn't Cartesian products, but NHibernate's identity map (aka 1st level cache). When loading an object from a resultset, NH first checks whether it already has the ID in its identity map. If so, it uses that object. Otherwise it creates a new one and sticks it in the identity map. This avoids update problems and circular reference problems."

"Update problem: If we didn't have the identity map... Load the same Customer twice. Get back two different customer objects. Update each customer object and save. What is in the database? Last update wins."

"Circular ref problem: If we didn't have the identity map... Load a Customer. Customer contains an Order. Load the Order. Guess what! It contains a Customer. Which contains an Order. Which contains a Customer... Lather, rinse, repeat."

"The 1st level cache is tied to the session. When the session is closed, the first level cache goes away. So you need to map the PersonInfo with a composite key - whatever makes it unique."

The Solution...

So, I don't have a unique primary key in the view, but NHibernate needs a unique key.  So the solution to my problem was, as James mentioned, to use a composite key.  Luckily, in this scenario, I could make a composite key. Each record for a person is only in the view once for each registered year.  So I needed to make a composite key that is the person identifier and registered year.

In this project, I am also using Fluent NHibernate. If you have not tried FN yet, you owe it to yourself to give it a run. Get rid of your XML mappings!  To my pleasant surprise, FN supports composite keys. Below is the class map for the Person object (VB lambdas aren't as pretty as the C# syntax).

Public Class PersonMap
    Inherits ClassMap(Of Person)
 
    Public Sub New()
        WithTable("personinfo_view")
        UseCompositeId() _
            .WithKeyProperty(Function(x As Person) x.Identifier, "pers_id") _
            .WithKeyProperty(Function(x As Person) x.RegisteredYear, "reg_year")
        Map(Function(x As Person) x.FirstName).TheColumnNameIs("pers_firstname")
        Map(Function(x As Person) x.LastName).TheColumnNameIs("pers_lastname")
        Map(Function(x As Person) x.PhoneNumber).TheColumnNameIs("pers_phone")
    End Sub
 
End Class

After adding in the composite key, NHibernate returned back the results I was expecting. Luckily this isn't a normal problem as most of the time you will have a unique id.

I hope this helps someone else.

Well, hopefully I'll have a good technical post soon, but while we wait for that I decided it would be a good idea to quickly share some of the events I'm planning on attending over the next month or so.

Edmonton Code Camp

On Saturday, November 29th, I'll be at Edmonton Code Camp.  This is an all day event which will have some pretty awesome sessions. View the wiki for details on speakers, sessions, geek dinner, etc.

Tech Days (Calgary)

On December 10-11, I'll be attending Tech Days in Calgary, which is a Microsoft event.  This little conference has a Windows track and Web track for developers (I'll be jumping in and out of both). There are also some other sessions related to Virtualization, Data Management, & Infrastructure.  All attendees will receive a "learning kit" which contains over $1000 worth of software; but the thing I'm most excited about is the TechEd 2008 DVD set.

DevTeach

Just a little reminder that DevTeach is happening in Montreal on December 1-5.  I won't be in Montreal, but I'm planning on going to the next one (Vancouver?).  There has also been discussion around planning another ALT.NET Canada conference around the next DevTeach; I'll post more info on that in the new year.

Hope to see you at Code Camp or Tech Days. If you see me, say hello!

Brandon Lang

Welcome

Welcome to my new blog.  I've been wanting / planning to set up to set up this blog for several months; I finally found some time to do it!

This blog exists for two main reason:

  1. To share information and network with other .NET developers.
  2. A central place for me to store new information I learn so I can reference it in the future.

The content of this blog is primarily going to be related to .NET software development; however, I'm sure other completely random topics will squeak in once in a while.

Who's Blang?

My name is Brandon Lang and I am a .NET software developer in Edmonton, Alberta, Canada.

Professional Life

Over the last 10 years or so, I've been quite interested in web development; however, it was really just a little hobby.  I didn't get serious about programming until I enrolled in the software development course at DevStudios.  I graduated in August 2007 and my life of working in the oilfield was officially over!!  I immediately got involved in my local .NET User Group so that I could a) continue my learning; and b) surround myself with developers that I could network with and feed off their knowledge and experience.  It was through this networking that I met Dave Woods, a fellow .NET developer here in Edmonton (And now a Microsoft MVP in security).  Dave needed someone to help him out with one of his current contracts and I needed work; it was a perfect fit.

The knowledge I gained in school was essential, but the information I have gained by surrounding myself with people like Dave, Donald Belcham, Tom Opgenorth, Justice Gray, James Kovacs (just to name a few) has launched me into a whole new world of software development.  In April of this year, I had the opportunity to attend the ALT.NET conference in Seattle.  I had the privilege of meeting many other leaders in the .NET community including Oren Eini, Greg Young, David Laribee, Scott Hanselman, Phil Haack, Scott Guthrie (again, just to name a few).  This open spaces conference helped increase my knowledge on development topics and techniques that I have been learning / hearing about including Agile, TDD, BDD, SRP, DI, O/RM, and so much more.  By no means do I consider myself an expert on any of these topics; I have just scratched the surface of some of them.  My hope is that as I post information that I have learned on this blog, I will get valuable feedback and comments from you, the reader.

Other things that I am interested in and in the process of learning (related to .NET) are:

  • Silverlight
  • JQuery
  • NHibernate
  • IronRuby
  • C# 4.0
  • and more...

Personal Life

Just a little bit about me.  As of writing, I'm 24 years old.  I am very happily married to my beautiful wife, Robynn.  We are both born-again Christians who love serving God, going to church and spending time with our church family.  Some of my other hobbies are: watching the Oilers, playing Poker, reading software related books, tweeting, gaming (Halo 3, Gears of War, NHL games), facebooking, raquetball, anything to do with my iPhone, eating peanut butter.

Thank you, come again!

I think that'll wrap it up for post number 1.  Please feel free to send me a message anytime.  I'd love to hear from you; whether it's a question, comment, threat, or just to connect.  Don't forget to subscribe to my RSS feed so you get updated on every new post.  Also, make sure to check out some of the other blogs listed in the Blogroll.  Those guys are WAY smarter than me!  They are the ones I go to and learn from!

Thanks for stopping by!

Brandon Lang