More NHibernate woes - the elusive hbm file

Hi,
I have a solution with 3 projects (the usual GUI / Business / Database trinity). I have all the hbm files in a folder called ‘mappings’ under the database project for the purpose of neatness and order.
I get an error when creating the Configuration object:

Configuration cfg = new Configuration();
cfg.Properties[“hibernate.connection.provider”] =
“NHibernate.Connection.DriverConnectionProvider”;
cfg.Properties[“hibernate.dialect”] =
“NHibernate.Dialect.MsSqlCeDialect”;
cfg.Properties[“hibernate.connection.driver_class”] =
“NHibernate.Driver.SqlServerCeDriver”;
cfg.Properties[“hibernate.connection.connection_string”] = path;
cfg.AddXmlFile(“Mappings\Project.hbm.xml”);
sessionFactory = cfg.BuildSessionFactory();

The error occurs on the 5th line where I add the hbm file:
Themis.Utilities.ThemisException: Failed to open connection to the
application. —> NHibernate.MappingException: Could not configure
datastore from file Mappings\Project.hbm.xml —>
System.IO.DirectoryNotFoundException: Could not find a part of the
path ‘D:\Documents\My Documents\Visual Studio 2010\Projects\Themis
\Themis\bin\Debug\Mappings\Project.hbm.xml’.

Now D:\Documents\My Documents\Visual Studio 2010\Projects\Themis\Themis\bin
\Debug\ is the path of the GUI project.

I tried the same code with:
cfg.AddXmlFile(“Project.hbm.xml”);
But got the same result.

The hbm file has the build attribute set to ‘EmbeddedResouce’. What am
I doing wrong?

If you’re embedding mapping files into your assembly, you need to add your assembly to the configuration:


Configuration config = new Configuration();
Configuration currentconfiguration = config.AddAssembly(this.GetType().Assembly);
ISessionFactory factory = currentconfiguration.BuildSessionFactory();

I didn’t understand why you declared 2 Configuration instances. I added this line:
cfg.AddAssembly(this.GetType().Assembly);

So my code looks like this:

Configuration cfg = new Configuration();
cfg.AddAssembly(this.GetType().Assembly);
cfg.Properties[“hibernate.connection.provider”] =
“NHibernate.Connection.DriverConnectionProvide r”;
cfg.Properties[“hibernate.dialect”] =
“NHibernate.Dialect.MsSqlCeDialect”;
cfg.Properties[“hibernate.connection.driver_class”] =
“NHibernate.Driver.SqlServerCeDriver”;
cfg.Properties[“hibernate.connection.connection_string”] = path;
cfg.AddXmlFile(“Mappings\Project.hbm.xml”);
sessionFactory = cfg.BuildSessionFactory();

Its finding the file now so it seems to work. Thanks.

I was too happy too soon :(

I now get this error:
NHibernate.MappingException: Could not compile the mapping document:
Themis.DatabaseServer.Mappings.Project.hbm.xml —>
System.InvalidOperationException: Could not find the dialect in the
configuration

My code looks like this:

Configuration cfg = new Configuration();
cfg.Properties[“hibernate.connection.provider”] =
“NHibernate.Connection.DriverConnectionProvider”;
cfg.Properties[“hibernate.dialect”] =
“NHibernate.Dialect.MsSqlCeDialect”;
cfg.Properties[“hibernate.connection.driver_class”] =
“NHibernate.Driver.SqlServerCeDriver”;
cfg.Properties[“hibernate.connection.connection_string”] = path;
cfg.AddAssembly(this.GetType().Assembly);
cfg.AddXmlFile(“Project.hbm.xml”);
sessionFactory = cfg.BuildSessionFactory();

Are you using Visual Studio? If so, put the hibernate-mapping and config scheme files in your VS XML directory and verify if your HBM files have the right structure.

As for the error about the dialect: did you include the DLL for the dialect? This any help?

I’m doing the configuration through code so there is no config file. Is this an issue?

Please please someone respond.

This article uses “dialect” instead of 'hibernate.dialect" as a config key.

Thanks, that solved that issue. Now the next. I’m starting to think about going back to ADO and DataSets. Setting up NHibernate sure is a chore.

Without getting into an ORM debate (makes P&R look like preschool) I’ll throw this out: if you’re using visual studio, just throw all your tables into a Linq2Sql datacontext and be done with it. The tooling is built in, it’s dead simple, and it works fine for 90% of cases. I’m pretty sure that most objections to it come from people who just think that nothing with GUI tools can be “powerful” enough. You can always switch later after playing with NHib for a while but in the meantime you’ve shipped an app. Time spent on non-domain problems is expensive. You are not your ORM.

I make one more effort before I throw the towel. I tried to include as much information as possible.

This is my solution structure:
GUI - winform project
ApplicationServer.dll
DatabaseServer.dll
DataEntities.dll

The hbm files are stored in a directory in the DatabaseServer.dll (Database\Mappings)
The domain classes are included in the DataEntities.dll

For now I only included only one hbm file. Its build action is set to ‘Embedded Resource’:

<?xml version=“1.0” encoding=“utf-8” ?>
<hibernate-mapping
assembly=“DataEntities”
namespace=“DataEntities”
xmlns=“urn:nhibernate-mapping-2.2” auto-import=“true”>
<class name=“Project” table=“PROJECTS”>
<id name=“PK” column=“PK” access=“nosetter.camelcase”>
<generator class=“native”/>
</id>
<property name=“Name” column=“NAME”/>
<property name=“Id” column=“ID”/>
<property name=“Description” column=“DESCRIPTION”/>
</class>
</hibernate-mapping>

The application will use sdf files that the user can switch so all the configuration is done through code. This code is included in DatabaseServer.dll:

Configuration cfg = new Configuration();

cfg.Properties["connection.provider"] = "NHibernate.Connection.DriverConnectionProvider";
cfg.Properties["dialect"] = "NHibernate.Dialect.MsSqlCeDialect";
    cfg.Properties["hibernate.connection.driver_class"] = "NHibernate.Driver.SqlServerCeDriver";
    cfg.Properties["hibernate.connection.connection_string"] = path;

cfg.AddAssembly(this.GetType().Assembly);
    cfg.AddXmlFile("Mappings\\Project.hbm.xml"); -&gt;&gt; ERROR HERE
    sessionFactory = cfg.BuildSessionFactory();

An error is thrown when the code is adding the hbm file:

NHibernate.MappingException: Could not configure datastore from file Mappings\Project.hbm.xml —> System.IO.DirectoryNotFoundException: Could not find a part of the path ‘D:\Documents\my documents\Visual Studio 2010\Projects\Application\GUI\bin\Debug\Mappings\Project.hbm.xml’.

Looking in the debug folder under the GUI project, I can see that there is no Mapping folder in it. Why is NHIbernate looking for it. Its supposed to be embedded in the DatabaseServer.dll.

Does your hbm file also have Copy if newer/copy always set? If not, it won’t get output to the directory IIRC. Also check if the path is correct using System.IO.File.Exists(“Mappings\Project.hbm.xml”). You may need to give an absolute path.

But if you’re embedding your hbm file and you’re already including the assembly in your NHib configuration there’s no need to add the hbm file via filesystem.

NHib is indeed a tough nut to crack in the beginning, and for really simple stuff you might get along just as well with Linq2Sql but for anything more complicated it’s definitely a beautiful thing. Once you understand it ;)

Man do I feel your pain. I just went through this whole exercise. We are trying to decide which ORM tech to go with, NHibernate or Entity Framework. For such a widely used framework NHibernate’s documentation sure does suck. This is my first experience with ORM and its making me want to stab my eyes out.

I tried to copy the file to the bin directory. I got this error:
NHibernate.MappingException: Could not compile the mapping document: Mappings\Project.hbm.xml —> NHibernate.DuplicateMappingException: Duplicate class/entity mapping DataEntities.Project

I suppose I’ll check Linq2Sql.

For anyone who’s interested, I got the answer at nhusers. This
cfg.AddXmlFile(“Mappings\Project.hbm.xml”)
is redundant as the mapping file is already loaded from the assembly a line before.

I managed to solve 2 more issues after that by googling NH exception messages ;)