Introduction
NHibernate is an object-relational mapping (ORM) framework, it allows you to map the object oriented domain model with the tables in a relational database. To realize the mapping, we have to write XML mapping files (.hbm.xml files), and to make it easier, here comes Fluent NHibernate as an abstraction layer to do it in C# rather than XML.
Databases supported by NHibernate are:
- SQL Server
- SQL Server Azure
- Oracle
- PostgreSQL
- MySQL
- SQLLite
- DB2
- Sybase Adaptive Server
- Firebird
- Informix
It can support even the use of OLE DB (Object Linking and Embedding), even ODBC (Open Database Connectivity).
What makes NHibernate stronger than Entity Framework is that it integrates querying API set like LINQ, Criteria API (implementation of the pattern Query Object), integration with Lucene.NET, use of SQL even stored procedures…
NHibernate also supports:
- Second Level cache (used among multiple
ISessionFactory
) - Multiple way of ID generation such as
Identity
, Sequence
, HiLo
, Guid
, Pooled
even Native
mechanism used in databases - Flushing properties (
FlushMode
properties in ISession
that can take these values: Auto
or Commit
or Never
) - Lazy Loading
- Generation and updating system like migration API in Entity framework (like Code First).
When Microsoft started working on the framework Core, much functionality in NHibernate wasn’t supported in .NET Core as target platform, but from the version Core 2.0, we can integrate NHibernate, even Fluent NHibernate.
Background
We should have a previous idea about NHibernate and Fluent NHibernate.
The IDE used in this sample is Visual Studio 2017.
NuGet Package
The NuGet package to use Fluent NHibernate:
PM> Install-Package FluentNHibernate -Version 2.1.2
Create Entities
This folder will include two entities: Person
and Task
.
Person Entity
public class Person
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual DateTime CreationDate { get; set; }
public virtual DateTime UpdatedDate { get; set; }
}
Task Entity
public class Task
{
public virtual string Id { get; set; }
public virtual string Title { get; set; }
public virtual string Description { get; set; }
public virtual DateTime CreationTime { get; set; }
public virtual TaskState State { get; set; }
public virtual Person AssignedTo { get; set; }
public virtual DateTime CreationDate { get; set; }
public virtual DateTime UpdatedDate { get; set; }
public Task()
{
CreationTime = DateTime.UtcNow;
State = TaskState.Open;
}
}
public enum TaskState : byte
{
Open = 0,
Active = 1,
Completed = 2,
Closed = 3
}
Create Mappings
This folder will contain the mapping classes for the previous entities.
PersonMap
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Id(x => x.Id);
Map(x => x.Name);
Map(x => x.CreationDate);
Map(x => x.UpdatedDate);
}
}
TaskMap
public class TaskMap : ClassMap<Task>
{
public TaskMap()
{
Id(x => x.Id);
Map(x => x.CreationTime);
Map(x => x.State);
Map(x => x.Title);
Map(x => x.Description);
Map(x => x.UpdatedDate);
Map(x => x.CreationDate);
References(x => x.AssignedTo);
}
}
Create the SessionFactory Builder
The SessionFactories folder will include the class of SessionFactoryBuilder
that will manage the schema builder and SessionFactory
builder.
public class SessionFactoryBuilder
{
public static ISessionFactory BuildSessionFactory
(string connectionStringName, bool create = false, bool update = false)
{
return Fluently.Configure()
.Database(PostgreSQLConfiguration.Standard
.ConnectionString(ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString))
.Mappings(m =>m.FluentMappings.AddFromAssemblyOf<NHibernate.Cfg.Mappings>())
.CurrentSessionContext("call")
.ExposeConfiguration(cfg => BuildSchema(cfg, create, update))
.BuildSessionFactory();
}
private static void BuildSchema(Configuration config, bool create = false, bool update = false)
{
if (create)
{
new SchemaExport(config).Create(false, true);
}
else
{
new SchemaUpdate(config).Execute(false, update);
}
}
}
Create Services
This folder will include all different treatment that we can do like GetAll
element of an Entity, add new element in database for example, in this sample, I will include two services according to our entities.
PersonService
public class PersonService
{
public static void GetPerson(Person person)
{
Console.WriteLine(person.Name);
Console.WriteLine();
}
}
TaskService
public class TaskService
{
public static void GetTaskInfo(Task task)
{
Console.WriteLine(task.Title);
Console.WriteLine(task.Description);
Console.WriteLine(task.State);
Console.WriteLine(task.AssignedTo.Name);
Console.WriteLine();
}
}
Add and display Table content
Now, we will try to display data from database or add a new element.
In the program, we will start by creating a session factory using the method: BuildSessionFactory
implemented inside the class SessionFactoryBuilder
after, we will open a new Session
for every Transaction
done. We start a new Transaction
inside, and it depends on the operation, if we need to insert a new line in the database, we use session.SaveOrUpdate(MyObjectToAdd);
after we commit this using this transaction: transaction.Commit();
static void Main(string[] args)
{
string connectionStringName = "add here your connection string";
var sessionFactory =
SessionFactoryBuilder.BuildSessionFactory(connectionStringName, true, true);
using (var session = sessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction()
{
var person1 = new Person { Name = "Rayen Trabelsi" };
var person2 = new Person { Name = "Mohamed Trabelsi" };
var person3 = new Person { Name = "Hamida Rebai" };
var task1 = new Task
{Title = "Task 1", State = TaskState.Open, AssignedTo = person1};
var task2 = new Task
{ Title = "Task 2", State = TaskState.Closed, AssignedTo = person2 };
var task3 = new Task
{ Title = "Task 3", State = TaskState.Closed, AssignedTo = person3 };
session.SaveOrUpdate(task1);
session.SaveOrUpdate(task2);
session.SaveOrUpdate(task3);
transaction.Commit();
}
using (var session2 = sessionFactory.OpenSession())
{
using (session2.BeginTransaction())
{
var tasks = session.CreateCriteria(typeof(Task))
.List<Task>();
foreach (var task in tasks)
{
TaskService.GetTaskInfo(task);
}
}
}
Console.ReadKey();
}
}
}
Conclusion
This sample is a sample use of Fluent NHibernate, in another article; I will show you another web sample using some of advantages like Criteria
APIs.
History
This sample is the same that we used when we worked using EF Core 2.0 as ORM.
See this article: