The other day, I found myself creating a bunch of new NHibernate object mapping files for the project I'm working on now. To test these, I had created a simple test case to ensure that the mapping files were valid by invoking BuildSessionFactory on the Configuration object (with the appropriate assemby containing the mapping files specified in AddAssembly). This is all fine and good, but if you have multiple mapping files being tested in one test, it's not a very isolated test. I set out to break up my mapping file tests into separate test cases. This proved to be a pain in the ass, simply because of the confusion I had around loading a single mapping file into the configuration.
There are many ways to initialize an NHibernate session with your class mappings (AddAssembly, AddClass, AddResource, AddFile, AddDirectory, AddInputStream....), but I wanted to get the "automatic" discovery functionality that you get when using AddClass or AddAssembly for a single mapping file (*.hbm.xml). I thought this would be a simple, straight-forward exercise.
What I wanted to do was specify a single Class.hbm.xml file to load and validate against the persistent class to which it is mapped. After reading through the NHibernate docs, I figured that AddResource would probably be my best bet as it lets me specify a direct path to the resource (in this case a mapping file). The AddResource signature looks like so:
/// <summary>
/// Adds the mappings in the resource of the assembly.
/// </summary>
/// <param name="path">The path to the resource file in the assembly.</param>
/// <param name="assembly">The assembly that contains the resource file.</param>
/// <returns>This configuration object.</returns>
public Configuration AddResource(string path, Assembly assembly)
After unsuccessfully attempting many different naming conventions for the path and scouring the documentation and the 'net for documentation, I finally resorted to the NHibernate source for the answer (man, I love open source software :) ). It turns out that NHibernate is using the Assembly class's GetManifestResourceStream() method in AddResource. After reading a couple of others' posts about having trouble with the syntax for GetManifestResourceStream(), I decided to do a couple tests to see what was going on here.
I like to create a separate project specifically for NHibernate resources. Keeping with this convention, I setup a test project (see image below) to test the resource path requirements.
By calling GetManifestResourceNames() on my ResourceTesting.NHibernateMappings assembly, you can see what format that GetManifestResourceStream() is expecting:
Console Output
ResourceTesting.NHibernateMappings.Subfolder.ClassMapping.hbm.xml
ResourceTesting.NHibernateMappings.ClassMapping.hbm.xml
Armed with the knowledge of the resource path syntax, I can now create a test to load a single mapping file from an assembly using NHibernate's AddResource method with the proper path syntax. Here's a sample test. I will likely refactor this for reuse to allow mapping file path inference based on the persistent class type, but this demonstrates the concept.
[Test]
public void Should_map_single_class()
{
Assembly assembly = Assembly.Load("ResourceTesting.NHibernateMappings");
configuration = configuration.AddResource("ResourceTesting.NHibernateMappings.ClassMapping.hbm.xml", assembly);
Assert.AreEqual(configuration.ClassMappings.Count, 1);
// NHibernate won't try to map to the persistent class
// unless you BuildSessionFactory
configuration.BuildSessionFactory();
}
The thing that bugs me about the GetManifestResourceStream call is that you call it on an Assembly instance. Why not have this call infer the fully-qualified resource path from the instance? Then, I could just pass in the resource name. There are probably reasons of which I'm not aware for the decision not to infer the full path, so in lieu of this being implemented in the .NET framework or NHibernate, I hope this helps someone else struggling with resources and NHibernate.