Introduction
For people that don't know what NHibernate is.
"NHibernate is a mature, open source object-relational mapper for the .NET framework.
It's actively developed, fully featured and used in thousands of successful projects."
Source
This "NHibernate: Getting started guide" post will explain the basics and how to use NHibernate with:
.NET Core 3.1
NHibernate 5.3.2
NUnit 3.12.0
SQLite 1.0.113.1
NuGet
Used techniques and design patterns
NHibernate Mapping by code
Repository
Domain Model
Unit testing
Source code
You can find the source code of this post on:
https://github.com/gergroen/NHibernate-getting-started-guide
Post summary
Installing NuGet
Download NHibernate, SQLite and NUnit with NuGet
Create and test a domain model
Create and test NHibernate mapping by code
Configure NHibernate for SQLite
Create and test a NHibernate helper
Create and test a repository
Installing NuGet
First
install the NuGet Package Manager if it is not installed.
Download NHibernate, SQLite and NUnit with NuGet
NHibernate
Now you can open the
"NuGet Package Manager" by clicking with the right mouse button on your project and choose "
Manage NuGet Packges..."
Search for "
NHibernate" and click on Install.
Two references are added to your project "
NHibernate" and "
Iesi.Collections".
"
Iesi.Collections" is added because "
NHibernate" has a dependency on "
Iesi.Collections".
SQLite
Start the "
NuGet Package Manager" again, search for "
System.Data.SQLite.Core" and click on Install.
NUnit
Start the "NuGet Package Manager" again, search for "NUnit" and click on install.
To run the unit tests in Visual Studio you can use tools like
ReSharper or
Testdriven.net.
If you don't need to run the unit tests in Visual Studio you can download the "
NUnit.Runners" via NuGet.
"
NUnit.Runners" allows you to run the unit tests through the command line or a gui.
Create and test a domain model
After downloading all the packages we can start with the domain model.
First we create a simple "
Person" domain model with the properties "
Id", "
FirstName" and a "
LastName".
Also we include the method "
GetFullName();".
using System;
namespace NHibernate.GettingStarted.Model
{
public class Person
{
public virtual Guid Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual string GetFullName()
{
return string.Format("{0} {1}", FirstName, LastName);
}
}
}
After creating the domain model we create a test class to test the domain model.
We're using "
NUnit" to unit test our domain model.
using NHibernate.GettingStarted.Model;
using NUnit.Framework;
namespace NHibernate.GettingStarted.Test
{
[TestFixture]
public class PersonTest
{
[Test]
public void GetFullNameTest()
{
var person = new Person
{
FirstName = "Test",
LastName = "Kees"
};
Assert.AreEqual("Test", person.FirstName);
Assert.AreEqual("Kees", person.LastName);
Assert.AreEqual("Test Kees", person.GetFullName());
}
}
}
Create and test NHibernate mapping by code
You can create the NHibernate mapping for your domain models in different ways. In this example i use NHibernate mapping by code.
using NHibernate.GettingStarted.Model;
using NHibernate.Mapping.ByCode;
using NHibernate.Mapping.ByCode.Conformist;
namespace NHibernate.GettingStarted.Dao
{
public class PersonMap : ClassMapping<Person>
{
public PersonMap()
{
Id(x => x.Id, m => m.Generator(Generators.GuidComb));
Property(x => x.FirstName);
Property(x => x.LastName);
}
}
}
To see the result of the mapping we create this unit test.
The test output is the traditional xml NHibernate mapping.
using System;
using System.Xml.Serialization;
using NHibernate.GettingStarted.Dao;
using NHibernate.Mapping.ByCode;
using NUnit.Framework;
namespace NHibernate.GettingStarted.Test
{
[TestFixture]
public class PersonMapTest
{
[Test]
public void CanGenerateXmlMapping()
{
var mapper = new ModelMapper();
mapper.AddMapping<PersonMap>();
var mapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
var xmlSerializer = new XmlSerializer(mapping.GetType());
xmlSerializer.Serialize(Console.Out, mapping);
}
}
}
Test output:
<?xml version="1.0" encoding="Windows-1252"?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" namespace="NHibernate.GettingStarted.Model" assembly="NHibernate.GettingStarted" xmlns="urn:nhibernate-mapping-2.2">
<class name="Person">
<id name="Id" type="Guid">
<generator class="guid.comb" />
</id>
<property name="FirstName" />
<property name="LastName" />
</class>
</hibernate-mapping>
Configure NHibernate for SQLite
To configure NHibernate we need to create a "nhibernate.cfg.xml" file and set the Copy to Output Directory to "Copy Always".
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory name="NHibernate.Test">
<property name="connection.driver_class">NHibernate.Driver.SQLite20Driver</property>
<property name="connection.connection_string">Data Source=test.db;Version=3;New=True</property>
<property name="dialect">NHibernate.Dialect.SQLiteDialect</property>
<property name="show_sql">true</property>
</session-factory>
</hibernate-configuration>
Create and test a NHibernate helper
Now we create a NHibernate helper class to load the configuration and the mapping to create sessions.
using System.Collections.Generic;
using NHibernate.Cfg;
using NHibernate.Cfg.MappingSchema;
using NHibernate.Mapping.ByCode;
namespace NHibernate.GettingStarted.Dao
{
public static class NHibernateHelper
{
private static ISessionFactory _sessionFactory;
private static Configuration _configuration;
private static HbmMapping _mapping;
public static ISession OpenSession()
{
//Open and return the nhibernate session
return SessionFactory.OpenSession();
}
public static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
//Create the session factory
_sessionFactory = Configuration.BuildSessionFactory();
}
return _sessionFactory;
}
}
public static Configuration Configuration
{
get
{
if (_configuration == null)
{
//Create the nhibernate configuration
_configuration = CreateConfiguration();
}
return _configuration;
}
}
public static HbmMapping Mapping
{
get
{
if (_mapping == null)
{
//Create the mapping
_mapping = CreateMapping();
}
return _mapping;
}
}
private static Configuration CreateConfiguration()
{
var configuration = new Configuration();
//Loads properties from hibernate.cfg.xml
configuration.Configure();
//Loads nhibernate mappings
configuration.AddDeserializedMapping(Mapping, null);
return configuration;
}
private static HbmMapping CreateMapping()
{
var mapper = new ModelMapper();
//Add the person mapping to the model mapper
mapper.AddMappings(new List<System.Type> { typeof(PersonMap) });
//Create and return a HbmMapping of the model mapping in code
return mapper.CompileMappingForAllExplicitlyAddedEntities();
}
}
}
Database schema test
using System;
using NHibernate.Tool.hbm2ddl;
using NUnit.Framework;
namespace NHibernate.GettingStarted.Dao.Test
{
[TestFixture]
public class SchemaTest
{
[Test]
public void CanGenerateSchema()
{
var schemaUpdate = new SchemaUpdate(NHibernateHelper.Configuration);
schemaUpdate.Execute(Console.WriteLine, true);
}
}
}
Test output:
create table Person (
Id UNIQUEIDENTIFIER not null,
FirstName TEXT,
LastName TEXT,
primary key (Id)
)
Create and test a Repository
With the NHibernateHelper we can create a person repository to save, get, update and delete persons to the SQLite database.
First we create a repository interface.
using System;
namespace NHibernate.GettingStarted.Model
{
public interface IPersonRepository
{
/// <summary>
/// Get person entity by id
/// </summary>
/// <param name="id">id</param>
/// <returns>person</returns>
Person Get(Guid id);
/// <summary>
/// Save person entity
/// </summary>
/// <param name="person">person</param>
void Save(Person person);
/// <summary>
/// Update person entity
/// </summary>
/// <param name="person">person</param>
void Update(Person person);
/// <summary>
/// Delete person entity
/// </summary>
/// <param name="person">person</param>
void Delete(Person person);
/// <summary>
/// Row count person in db
/// </summary>
/// <returns>number of rows</returns>
long RowCount();
}
}
Repository class
using System;
using NHibernate.GettingStarted.Model;
namespace NHibernate.GettingStarted.Dao
{
public class NHibernatePersonRepository : IPersonRepository
{
public void Save(Person person)
{
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Save(person);
transaction.Commit();
}
}
public Person Get(Guid id)
{
using (ISession session = NHibernateHelper.OpenSession())
return session.Get<Person>(id);
}
public void Update(Person person)
{
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Update(person);
transaction.Commit();
}
}
public void Delete(Person person)
{
using (ISession session = NHibernateHelper.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Delete(person);
transaction.Commit();
}
}
public long RowCount()
{
using (ISession session = NHibernateHelper.OpenSession())
{
return session.QueryOver<Person>().RowCountInt64();
}
}
}
}
Repository test
using System.IO;
using NHibernate.GettingStarted.Model;
using NHibernate.Tool.hbm2ddl;
using NUnit.Framework;
namespace NHibernate.GettingStarted.Dao.Test
{
[TestFixture]
public class NHibernatePersonRepositoryTest
{
private IPersonRepository _personRepo;
[SetUp]
public void CreateSchema()
{
DeleteDatabaseIfExists();
var schemaUpdate = new SchemaUpdate(NHibernateHelper.Configuration);
schemaUpdate.Execute(false, true);
_personRepo = new NHibernatePersonRepository();
}
[Test]
public void CanSavePerson()
{
_personRepo.Save(new Person());
Assert.AreEqual(1, _personRepo.RowCount());
}
[Test]
public void CanGetPerson()
{
var person = new Person();
_personRepo.Save(person);
Assert.AreEqual(1, _personRepo.RowCount());
person = _personRepo.Get(person.Id);
Assert.IsNotNull(person);
}
[Test]
public void CanUpdatePerson()
{
var person = new Person();
_personRepo.Save(person);
Assert.AreEqual(1, _personRepo.RowCount());
person = _personRepo.Get(person.Id);
person.FirstName = "Test";
_personRepo.Update(person);
Assert.AreEqual(1, _personRepo.RowCount());
Assert.AreEqual("Test", _personRepo.Get(person.Id).FirstName);
}
[Test]
public void CanDeletePerson()
{
var person = new Person();
_personRepo.Save(person);
Assert.AreEqual(1, _personRepo.RowCount());
_personRepo.Delete(person);
Assert.AreEqual(0, _personRepo.RowCount());
}
[TearDown]
public void DeleteDatabaseIfExists()
{
if (File.Exists("test.db"))
File.Delete("test.db");
}
}
}
Useful links:
Source code
NHibernate documentation