I was looking in my NHProf log and got a lot of SELECT request. To many and I thought I was having a SELECT N+1 problem.
Using the “Stack Trace” in NHprof I identified a call being made to GetHashCode() of the class (MyClass) holding the composite id. MyClass looked like this:
public class MyClass { public virtual Key1Class Key1 { get; set; } public virtual Key2Class Key2 { get; set; } /* * Other virtual properties * ... */ public override int GetHashCode() { unchecked { return ((Key1 != null ? Key1.GetHashCode() : 0) * 397) ^ (Key2 != null ? Key2.GetHashCode() : 0); } } }
Note that Key1 and Key2 are both references, and please take a closer look at the GetHashCode method.
The problem
The problem I was facing… NHibernate called the GetHashCode() of MyClass when doing the query. And the call to MyClass‘s GetHashCode method subsequentily called GetHashCode() of both the Key1 and Key2 classes.
Key1 and Key2 were loaded as proxies and hence a call to something else than theirs Id resulted in a select being fired.
The solution
The solution was to rewrite the GetHashCode method to this:
public override int GetHashCode() { unchecked { return ((Key1 != null ? Key1.Id : 0) * 397) ^ (Key2 != null ? Key2.Id : 0); } }
Note that both Id’s of KeyClass1 and KeyClass2 are integers.
Now a call to MyClass GetHashCode does not result in individual SELECT statements being fired, even though the Keys area lazy loaded.