NHibernate error while adding a collection to an object
I'll keep this one fairly Google-able due to the amount of time it took me to figure it out sans a similar reference. Seasoned NHibernate veterans will likely guess the issue before they finish reading this sentence.
Here's the error message I was getting from NHibernate:
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
at System.ThrowHelper.ThrowKeyNotFoundException()
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at NHibernate.Cfg.XmlHbmBinding.CollectionBinder.BindCollectionSecondPass(XmlNode node, Collection model, IDictionary`2 persistentClasses)
at NHibernate.Cfg.XmlHbmBinding.CollectionBinder.<>c__DisplayClassd.<AddCollectionSecondPass>b__c(IDictionary`2 persistentClasses)
at NHibernate.Cfg.Configuration.SecondPassCompile()
at NHibernate.Cfg.Configuration.BuildSessionFactory()
at Trilogy.Gunton.DataAccess.SessionBuilder.GetSessionFactory(Database selectedDatabase) in SessionBuilder.cs: line 72
at Trilogy.Gunton.DataAccess.SessionBuilder.GetSession(Database selectedDatabase) in SessionBuilder.cs: line 21
at Trilogy.Gunton.DataAccess.UnitOfWorkFactory.Create() in UnitOfWorkFactory.cs: line 19
at Trilogy.Gunton.DataAccess.RepositoryBase`1.GetAll() in RepositoryBase.cs: line 19
at Trilogy.Gunton.Tests.Integration.JobTypeRepositoryFixture.Should_retrieve_job_types() in JobTypeRepositoryFixture.cs: line 16
This started happening after I added a collection to my object (which Karl Seguin's post was instrumental in getting set up). Here's what I added to the <class> element in the .hbm.xml file for the object (fingers crossed on the XML formatting):
<bag name="Locations" generic="true"> <key column="JobID" /> <one-to-many class="RuralLocation" /> </bag>
Pretty standard stuff to those in the know (of which I am still not). I also created the corresponding RuralLocation class and RuralLocation.hbm files to go along with them.
So the above error would appear anytime I tried to get a session factory in NHibernate, which is pretty much the first thing that's done anywhere in the app. The ultimate solution: RuralLocation.hbm was not an embedded resource.
This is something I will forget to do about 75% of the time I create a new .hbm file but usually the error is more "oh yeah"-inducing. Something like "Can't find class Trilogy.Gunton.Domain.RuralLocation" where you can tell pretty quickly it's not loading the file properly. I know this because the way I discovered the problem is by creating an integration test to save a RuralLocation on its own, outside the context of its parent object.
In this case, because I went straight to using the new class in a collection within another object, the error was hair-tearingly cryptic. Luckily, I don't have much hair anyway so no harm done.
Kyle the Eggheaded