My application supports both Oracle and MS SQL databases, with slightly different schemas having been implemented for each. One issue I've run into is a class that has an auto-increment primary key under MS SQL, but a manually-inserted primary key under Oracle.
Right now, the two different mappings for the class look like this:
Oracle:
<class lazy="false" name="EntityPropertyName" table="entity_property_name" >
<id name="ID" column="id" type="Int32" unsaved-value="-1">
<generator class="increment" />
</id>
<property name="Name" column="name"/>
MS SQL:
<class lazy="false" name="EntityPropertyName" table="entity_property_name" >
<id name="ID" column="id" type="Int32" unsaved-value="-1">
<generator class="native">
</generator>
</id>
<property name="Name" column="name"/>
This isn't the worst thing in the world, because I can put them into different mapping files and load the correct one at runtime.
NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
if (newDBType == CompanyName.AppName.Data.Enum.DatabaseType.MsSqlServer)
{
cfg.Properties["dialect"] = "NHibernate.Dialect.MsSql2000Dialect";
cfg.Properties["connection.driver_class"] = "NHibernate.Driver.SqlClientDriver";
cfg.AddFile("DataTypes\\MSSQLTypes.hbm.xml");
}
else
{
cfg.Properties["dialect"] = "NHibernate.Dialect.Oracle9Dialect";
cfg.Properties["connection.driver_class"] = "NHibernate.Driver.OracleClientDriver";
cfg.AddFile("DataTypes\\OracleTypes.hbm.xml");
}
cfg.Properties["connection.provider"] = "NHibernate.Connection.DriverConnectionProvider";
cfg.Properties["connection.connection_string"] = connectionString;
cfg.AddAssembly("CompanyName.AppName.Data");
Sessions = cfg.BuildSessionFactory();
The thing I dislike about this strategy though is that I now have some ugly XML files in my program's bin directory, which need to be there or the application won't work. It would be a lot better if I could embed the different files into the resource like I can with my main mapping file, but choose whether to load each file or not at runtime.
Is there any way to do this, or perhaps a different way to solve the problem?
Edit: Thank you, Cristian! You did understand the question, I was just unaware that resources could be loaded by NHibernate like that. Thinking on it, I suppose it makes sense for the AddAssembly method would have to have some way to enumerate and load the resources that it finds!
My solution ended up being:
NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
if (newDBType == CompanyName.AppName.Data.Enum.DatabaseType.MsSqlServer)
{
cfg.Properties["dialect"] = "NHibernate.Dialect.MsSql2000Dialect";
cfg.Properties["connection.driver_class"] = "NHibernate.Driver.SqlClientDriver";
cfg.AddInputStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("CompanyName.AppName.Data.DataTypes.MSSQLTypes.hbm.xml"));
}
else
{
cfg.Properties["dialect"] = "NHibernate.Dialect.Oracle9Dialect";
cfg.Properties["connection.driver_class"] = "NHibernate.Driver.OracleClientDriver";
cfg.AddInputStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("CompanyName.AppName.Data.DataTypes.OracleTypes.hbm.xml"));
}
cfg.Properties["connection.provider"] = "NHibernate.Connection.DriverConnectionProvider";
cfg.Properties["connection.connection_string"] = connectionString;
cfg.AddInputStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("CompanyName.AppName.Data.DataTypes.Types.hbm.xml"));
Sessions = cfg.BuildSessionFactory();
I might be missing your crucial point. NHibernate is quite flexible in how you can feed it the mapping files. e.g.
or a custom built xml string:
You can also add mappings programmatically directly but that's a bit trickier.