views:

2179

answers:

1

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();
+1  A: 

I might be missing your crucial point. NHibernate is quite flexible in how you can feed it the mapping files. e.g.

cfg.AddInputStream(assembly.GetManifestResourceStream("MyNamespace.MyEmbeddedresource.hbm.xml"));

or a custom built xml string:

cfg.AddXml(myCustomBuildXmlString);

You can also add mappings programmatically directly but that's a bit trickier.

Cristian Libardo