NHibernate and Multiple Databases - Architecture

I have a project that should run on different (at least 2) database backends, so users can choose (currently between MSSQL and SQLite). I just started learning NHibernate following the tutorial on nhibernate.info .

Now my current architecture is as follows:

MyProject.DAL

Contains NewsItem and INewsItemRepository . NewsItem is a POCO, essentially just an identifier and a line identifier.

INewsItemRepository is an interface that enables CRUD functionality.

MyProject.Plugins.DAL.MSSQL

This class implements a backend. It includes hibernate.cfg.xml , NewsItem.hbm.xml and NewsItemRepository .

Cfg contains the driver and ConnectionString, hbm is the SQL-Server mapping, and NewsItemRepository implements INewsItemRepository.

If I want to add MyProject.Plugins.DAL.SQLite, I have to duplicate all this, which is logical. However, I wonder if this is correct? I feel like I over-duplicate things. I mean: I need to make sure that the mapping is database dependent, and that I will update all my plugins if the database changes. But this architecture still seems somehow ... bloated.

Am I doing the right thing here? Or are there common templates about what is included in the general business assembly and what needs to be stored separately for each database?

Edit: One of the problems here is handling sql types. For example, rows are displayed by default as nvarchar (255), and if I need ntext in MSSQL, I have to use the syntax <column sql-type = "NTEXT", right? I assume the definition of the sql type is database dependent, so do I need my mapping to be split into a database? Or is there a built-in mechanism for mappings to "inherit" each other? (Ie have one .hbm.xml with all the <property> tags in a common DAL project and then .hbm in each Backend-Assembly containing columns?

+4
source share
3 answers

Well, I have not seen your project or data model, so you will have to interpret this as the most appropriate for your situation. However, yes, my reaction is that this is more code than necessary.

One of the main advantages of using ORMs like NHibernate is that they separate your code from your persistence architecture. It seems to me that displaying a NewsItem (for example) several times is not necessary, for one. Can't the data model be the same regardless of the backend? Perhaps you could give an example of where they might differ.

Secondly, I probably wouldnโ€™t repeat the implementation of NewsItemRepository. Regardless of the database, NHibernate is used in the repository, the purpose of which is to abstract the database. All CRUD functions processed by the repository will be the same in MSSQL as SQLite (unless there really is a difference in the data model).

If your database model is the same for both parties, theoretically you only need to change the connection string to change the database used. The way I implemented DAL is to provide interfaces, as you did, and then have a namespace for implementations, one (well, the only one for now) that is NHibernate. Repositories and others are obtained by dependency injection. The DI core also handles session factories, so it's easy to target a different database for different sections of the code.

Of course, all this assumes that your data model is the same for both database engines. If not, my answer may not be very helpful. If this is the case, knowing that something else can lead me or someone else to a better answer.

EDIT:

I understand what you mean about sql type. However, this is only a problem if you generate a schema for your database from NHibernate. When mapping properties, you do not need to use <column> , and the type you specify on <property> is the type of NHibernate. The StringClob type correctly processes NTEXT fields.

If you are generating your schema from NHibernate mappings and NHibernate is not smart enough to exclude sql-type = "NTEXT" for SQLite (I hope so, but I never used the schema generation tool), I think I would add a step Builds to clean SQLite schemas. Of course, now you add complexity to your process, so it is up to you. However, I prefer that my code and mappings be as simple and clean as possible and only keep complexity where necessary (detailed information about the database engine). It seems to me that saving two separate mapping files is a recipe for not matching properties, and users have left scratching their heads about why they cannot use DOB when using SQLite;)

EDIT2 (regarding the use of DI with NH):

This is a bit subjective since I'm sure there are many ways to use DI with NHibernate. I have had great success using DI with Fluent NHibernate and Ninject , a DI framework that also uses smooth DSL. Fluent NHibernate (FNH) provides the IPersistenceConfigurer interface, which is used to create your database connection string (it also provides a number of dialects to choose from). Thus, it is easy to bind this IPersistenceConfigurer service to a provider through a DI framework. You can do the same for ISessionFactory to have a fully D-nested factory. Since Ninject works with attributes, my repository constructor might look like this:

 [Inject, CRM] public MyRepository(ISessionFactory sessionFactory) 

To enter a factory for the CRM database. I like.:)

+4
source

The data types used by NHibernate depend on the dialect used in your configuration file. When it processes the xml, it searches for the correct data type, depending on this dialect for each field. You would use a different dialect for each database, so you can use the same hbm.xml for the entire project.

+1
source

I process dynamically switching databases by setting up a factory session in code from the connection string in the configuration file. I decide which connection string to use by asking the user or reading application settings. I pass ISessionFactory or ISession to your repositories using dependency injection, usually passing it to the constructor.

I have no experience applying to multiple database providers, so I donโ€™t know what problems you will encounter because of this.

+1
source

All Articles