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.