Last Updated:

How to work with Fluent NHibernate in C#

This post will include an overview of the material I presented at the MCP club meeting on December 24, 2009, and slightly supplemented. It will be interesting to everyone who is interested in ORM technologies, DAL design and those who want to save time on development. Well, as they say Let's begin and all that. 🙂

Let's start first of all from the beginning. What is NHibernate? Sending you to Google would be pointless because you've probably already gone there. 🙂

In short, NHibernate is an (excellent) ORM technology based on two things:

The first thing is to use the business logic classes written by the developer as entities (POCO)

POCO = Plain old CLR objects, these classes consist most often of properties, their purpose is to store data.

The second thing is to use XML files to configure and describe mapping.

What is mapping? This is a reflection of the very classes that we wrote in the objects (tables, relationships) of the relational database.

NHibernate's main competitors are:

LINQ2SQL is the easiest way to describe business logic objects (entities) using the Microsoft Visual Studio designer. The main disadvantage is that this thing does not allow us to use ready-made classes written earlier. More precisely, it allows with very great difficulties, and requires inheritance from specialized classes. Quite heavy, although somewhat primitive.

The Microsoft Entity Framework is a serious competitor for NHibernate, but still somewhat lagging behind. For example, if you add a new property to an entity, it will take much longer to rebuild the database schema in EF. In addition, support for POCO-classes appeared relatively recently in the beta version.

UPDATE: One of the very big drawbacks is also the focus on Microsoft SQL Server for the above technologies. There are, of course, adapters written by enthusiasts, but no one guarantees you normal operation. NHibernate supports a large number of modern DBMSs and this is a big plus.

Where does NHibernate come from?

NHibernate comes from its older sister, Hinerbate, from the mysterious world of Java. It's not just a ported version, it's an attempt to look at some of the features and issues differently by using .NET features like reflection and CodeDOM. But without going into details, everything is very similar, and if you worked on Java with Hibernate, you will be able to understand NHibernate.

But for those who do not want to understand NHibernate (including) and this article 😉 is devoted

What's the problem?

Any technology has both pros and cons. Here are some disadvantages of NHibernate: difficulty in mastering, it takes a sufficiently high level to understand the features, the use of XML files makes it easy to make mistakes when writing mapping constructions, while there is no type control at the compilation stage, there is no syntax checking with all the ensuing ... But do not let this frighten you, as you will see from this material, these shortcomings can be circumvented in a very convenient and beautiful way.

Why Fluent NHibernate?

When I was going to study NHibernate (to be honest, I never fully learned it), I came across this wonderful fluent technology and it was all I needed. Because it really saves a lot of time, solves the tasks and has a bunch of goodies on board. Being an add-on to NHibernate, this thing allows you not to think about what XML files should look like, there is no XML at all! Type control, automatic connection of classes to mapping, the ability to conveniently configure the connection to the database, etc. etc.

In general, my decision is definitely FOR.

Where do you get that?

First, you need NHibernate to work with Fluent NHibernate. You can take it here: sourceforge.net/projects/nhibernate/

Second, take Fluent NHibernate directly here: fluentnhibernate.org/

Problem Statement

So, we have several classes of business logic (entities) that we are going to store in the database.

This is roughly what all of our entity classes will look like:

 

What's next?

Now you need to adapt the classes to work with NHibernate. There are a number of requirements, one of which is the use of the virtual keyword (required for Lazy Loading). In addition, you must enter a identifier (UID) to identify the entities in the database. To do this, we will use the base abstract class and inherit the main classes from it:

The rest of the classes for working with NHibernate will change slightly (note that instead of List<> there is an IList construct<>, because NHibernate uses its own internal implementation of lists):

The class diagram will remain the same.

Mapping

It's time to create mapping. As I mentioned – NO XML AT ALL – CODE ONLY!

For comparison, I'll show you what an example of XML mapping looks like (remember, it's all written by the hands of !!!!):

And this is how it will be written in the code:

(add a reference to the FluentNHibernate.Mapping namespace in the code)

So, now let's deal with these designs. We inherit mappings from the generic class ClassMap<>, which contains a number of protected methods, such as Map<>, References<>, Id<>, etc. Mapping is constructed in such a way that the specified class is stored in a table with the same name (unless otherwise specified by the Table method).

The Map method specifies that the property specified by the selector parameter will be mapped to a specific field in the table.

Id — indicates the identity and how it is generated.

References are many-to-one relationships. For example, References(x => x.Product) for mapping the Order class indicates that an Order can contain multiple Instances of Product and vice versa, each Product instance has a parent Instance of Order.

HasMany - Allows you to specify a one-to-many relationship for a parent class.

The methods are quite transparent and their names speak for themselves, you should not have problems with a more detailed question.

Set up your connection

To mount a database, we do the following (the database must exist):

That's so fast and convenient!

In the next part, we'll look at the IRepository template and how to configure automapping for our entities.

In the last part, we looked at the basic capabilities of Fluent NHibernate, learned how to build mapping. Now let's try to use all this to create a database and save/load entities in the database.

Let's break the task into subtasks:

  • Creating an NHibernate Configuration (Configuration Class)
  • Creating a database structure
  • Session and Transaction Management
  • Entity Management (CRUD)

So, we considered the configuration of the connection in the last part, here we will not focus on this, I will repeat only the code:

 

Structure of the database

 

To create a database structure in NHibernate, there is a utility class SchemaExport.

Executing the Create method will create all the tables and the relationships between them, according to the mappings described.

Session and Transaction Management

 

In the world of NHibernate, it is customary to use sessions to manipulate entities. The session represents the context of the connection to the database and performs entity tracking (tracks property changes, etc.). In addition, sessions support transactions. In order to create a session, we must first create a session factory (based on our configuration):

Now we have the ability to create sessions:

When we finish using the session, we reset its state to the database (Flush) and close it (Close).

Within sessions, we can and should use transactions (you know what they are?):

 

CRUD, IRepository template, Generic DAO and all...

 

The last thing left to do is to implement the ability to save and load our entities.

To do this, there is an NHibernate Best Practice recommendation – the use of Generic DAO.

As a special use case for this pattern, consider the repository implementation:

As you can see, our repository will be a generic implementation, this will allow you to use it for different types of entities.

The Save method in this case is responsible for both updating an existing entity in the database and creating a new entity.

Here's the repository implementation:

Well, now you're done, below is the code for creating and saving specific instances of entities:

Well, the code to load these entities:

p.s. In order to see string representations, you need to override the ToString() method

That's actually all, I hope you were interested and useful in this material.

In the near future, we will look at the possibilities of unit testing Fluent NHibernate using NUnit technology.

Here we will briefly consider it.

Do you remember what we did to map entities?

Created classes-descendants from ClassMap<>, specified properties for mapping, etc.

something like this:

To save time and minimize the code, all this can be avoided by creating an automapping code:

 

What is Conversions?

Conversions help us set the rules for creating auto mapping.

Here are some of them:

I think everything is clear here.

Now you need to change the configuration a little:

where mappings is the AutoPersistenceModel class that we instantiated earlier.

Ready! now our mappings are created automatically and there is no need to write no lines of manual mappin code, hooray!