NHibernate

NHibernate is a mature, highly flexible enterprise ORM for .NET. Developed as a C# port of Java Hibernate, it's an open-source OR/M framework with over 15 years of proven track record. It provides precise SQL control, multi-database support, enterprise-grade caching, and rich mapping methodologies, optimized for building complex enterprise systems. Through the Data Mapper pattern, it achieves separation between domain models and database schemas, delivering exceptional flexibility for legacy system integration and complex business logic implementation.

ORMC#.NETData MapperEnterpriseOpen Source

GitHub Overview

nhibernate/nhibernate-core

NHibernate Object Relational Mapper

Stars2,155
Watchers161
Forks935
Created:August 14, 2011
Language:C#
License:GNU Lesser General Public License v2.1

Topics

c-sharpcriteria-apidotnetdotnet-coredotnet-core2linqlinq-providernhibernatenhibernate-developersobject-relational-mapperorm

Star History

nhibernate/nhibernate-core Star History
Data as of: 8/13/2025, 01:43 AM

Library

NHibernate

Overview

NHibernate is a mature, highly flexible enterprise ORM for .NET. Developed as a C# port of Java Hibernate, it's an open-source OR/M framework with over 15 years of proven track record. It provides precise SQL control, multi-database support, enterprise-grade caching, and rich mapping methodologies, optimized for building complex enterprise systems. Through the Data Mapper pattern, it achieves separation between domain models and database schemas, delivering exceptional flexibility for legacy system integration and complex business logic implementation.

Details

NHibernate 2025 edition continues to be utilized on modern platforms as a mature ORM with .NET Core and .NET 5+ support. It provides diverse query description methods through HQL (Hibernate Query Language), Criteria API, and LINQ to NHibernate, addressing complex business requirements. It supports flexible configuration approaches including XML mapping, Fluent NHibernate, and Attribute-based mapping. Comprehensive performance optimization features for enterprise environments include multi-layered caching systems (First-Level Cache, Second-Level Cache, Query Cache), Lazy Loading, Batch Fetching, and Connection Pooling.

Key Features

  • Mature Data Mapper Pattern: Complete separation between domain models and database
  • Rich Query Methods: Trinity of HQL, Criteria API, and LINQ to NHibernate
  • Multi-database Support: 20+ RDBMS including Oracle, SQL Server, MySQL, PostgreSQL
  • Flexible Mapping: Diverse configuration methods via XML, Fluent, and Attributes
  • Enterprise Caching: Multi-layered caching and query optimization
  • Advanced Inheritance Mapping: Comprehensive support for Table per Hierarchy/Class/Subclass

Advantages and Disadvantages

Advantages

  • Solid position in enterprise field with over 15 years of stable track record
  • Advanced SQL control and flexible handling of complex business logic
  • Overwhelming advantage in integration with legacy database schemas
  • Rich documentation, books, and community resources
  • Transparency and freedom through open source (Apache License 2.0)
  • Continued availability on latest platforms with .NET 5/6/7/8 support

Disadvantages

  • Higher learning cost and configuration complexity compared to Entity Framework Core
  • Mapping configuration tends to be verbose, creating overhead for small projects
  • Limited support for modern development practices (Code First, Migrations)
  • Community-based support system without official Microsoft support
  • LINQ implementation not as complete as Entity Framework in some scenarios
  • High acquisition cost for new developers with significant team training burden

Reference Pages

Code Examples

Installation and Project Setup

# Install NuGet packages with .NET CLI
dotnet add package NHibernate
dotnet add package NHibernate.Mapping.Attributes
dotnet add package FluentNHibernate  # For Fluent mapping

# SQL Server driver
dotnet add package System.Data.SqlClient

# MySQL driver
dotnet add package MySql.Data

# PostgreSQL driver
dotnet add package Npgsql

# Console application creation example
dotnet new console -n NHibernateDemo
cd NHibernateDemo
<!-- Project file (.csproj) reference example -->
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="NHibernate" Version="5.5.2" />
    <PackageReference Include="NHibernate.Mapping.Attributes" Version="5.5.2" />
    <PackageReference Include="FluentNHibernate" Version="3.3.0" />
    <PackageReference Include="System.Data.SqlClient" Version="4.8.6" />
  </ItemGroup>

  <ItemGroup>
    <EmbeddedResource Include="Mappings\*.hbm.xml" />
  </ItemGroup>

</Project>

Basic Entity Definition and Mapping

// Domain/User.cs - Domain entity
using System;
using System.Collections.Generic;

namespace NHibernateDemo.Domain
{
    public class User
    {
        public virtual int Id { get; set; }
        public virtual string Username { get; set; }
        public virtual string Email { get; set; }
        public virtual string FirstName { get; set; }
        public virtual string LastName { get; set; }
        public virtual DateTime CreatedAt { get; set; }
        public virtual bool IsActive { get; set; }
        
        // One-to-Many relationship
        public virtual ISet<Post> Posts { get; set; } = new HashSet<Post>();
        
        // Computed property
        public virtual string FullName => $"{FirstName} {LastName}";
        
        // Business logic
        public virtual void Activate()
        {
            IsActive = true;
        }
        
        public virtual void Deactivate()
        {
            IsActive = false;
        }
    }
    
    public class Post
    {
        public virtual int Id { get; set; }
        public virtual string Title { get; set; }
        public virtual string Content { get; set; }
        public virtual DateTime CreatedAt { get; set; }
        public virtual DateTime? UpdatedAt { get; set; }
        public virtual bool Published { get; set; }
        
        // Many-to-One relationship
        public virtual User Author { get; set; }
        
        // One-to-Many relationship  
        public virtual ISet<Comment> Comments { get; set; } = new HashSet<Comment>();
    }
    
    public class Comment
    {
        public virtual int Id { get; set; }
        public virtual string Content { get; set; }
        public virtual DateTime CreatedAt { get; set; }
        
        // Many-to-One relationships
        public virtual User Author { get; set; }
        public virtual Post Post { get; set; }
    }
}

XML Mapping Configuration

<!-- Mappings/User.hbm.xml -->
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   namespace="NHibernateDemo.Domain"
                   assembly="NHibernateDemo">

  <class name="User" table="Users">
    <id name="Id" column="UserId" type="int">
      <generator class="identity" />
    </id>
    
    <property name="Username" column="Username" type="string" 
              length="50" not-null="true" unique="true" />
    <property name="Email" column="Email" type="string" 
              length="255" not-null="true" unique="true" />
    <property name="FirstName" column="FirstName" type="string" length="50" />
    <property name="LastName" column="LastName" type="string" length="50" />
    <property name="CreatedAt" column="CreatedAt" type="datetime" not-null="true" />
    <property name="IsActive" column="IsActive" type="boolean" not-null="true" />
    
    <!-- One-to-Many relationship -->
    <set name="Posts" table="Posts" cascade="all-delete-orphan" 
         lazy="true" inverse="true">
      <key column="AuthorId" />
      <one-to-many class="Post" />
    </set>
  </class>

</hibernate-mapping>

<!-- Mappings/Post.hbm.xml -->
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   namespace="NHibernateDemo.Domain"
                   assembly="NHibernateDemo">

  <class name="Post" table="Posts">
    <id name="Id" column="PostId" type="int">
      <generator class="identity" />
    </id>
    
    <property name="Title" column="Title" type="string" 
              length="200" not-null="true" />
    <property name="Content" column="Content" type="text" />
    <property name="CreatedAt" column="CreatedAt" type="datetime" not-null="true" />
    <property name="UpdatedAt" column="UpdatedAt" type="datetime" />
    <property name="Published" column="Published" type="boolean" not-null="true" />
    
    <!-- Many-to-One relationship -->
    <many-to-one name="Author" class="User" column="AuthorId" 
                 not-null="true" cascade="none" />
    
    <!-- One-to-Many relationship -->
    <set name="Comments" table="Comments" cascade="all-delete-orphan" 
         lazy="true" inverse="true">
      <key column="PostId" />
      <one-to-many class="Comment" />
    </set>
  </class>

</hibernate-mapping>

NHibernate Configuration and Session Factory

// Configuration/NHibernateHelper.cs
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System.Reflection;

namespace NHibernateDemo.Configuration
{
    public static class NHibernateHelper
    {
        private static ISessionFactory _sessionFactory;
        private static readonly object Lock = new object();

        public static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    lock (Lock)
                    {
                        if (_sessionFactory == null)
                        {
                            _sessionFactory = BuildSessionFactory();
                        }
                    }
                }
                return _sessionFactory;
            }
        }

        private static ISessionFactory BuildSessionFactory()
        {
            try
            {
                var configuration = new NHibernate.Cfg.Configuration();
                
                // Database configuration
                configuration.SetProperty("connection.driver_class", 
                    "NHibernate.Driver.SqlClientDriver");
                configuration.SetProperty("connection.connection_string", 
                    "Server=localhost;Database=NHibernateDemo;Integrated Security=true;TrustServerCertificate=true");
                configuration.SetProperty("dialect", 
                    "NHibernate.Dialect.MsSql2012Dialect");
                
                // Basic settings
                configuration.SetProperty("show_sql", "true");
                configuration.SetProperty("format_sql", "true");
                configuration.SetProperty("hbm2ddl.auto", "update"); // create, update, validate
                
                // Cache settings
                configuration.SetProperty("cache.use_second_level_cache", "true");
                configuration.SetProperty("cache.provider_class", 
                    "NHibernate.Cache.HashtableCacheProvider");
                configuration.SetProperty("cache.use_query_cache", "true");
                
                // Batch processing settings
                configuration.SetProperty("adonet.batch_size", "20");
                
                // Add mapping files
                configuration.AddAssembly(Assembly.GetExecutingAssembly());
                
                return configuration.BuildSessionFactory();
            }
            catch (Exception ex)
            {
                throw new Exception("SessionFactory creation error", ex);
            }
        }

        public static ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }

        public static void CloseSessionFactory()
        {
            if (_sessionFactory != null)
            {
                _sessionFactory.Close();
            }
        }
    }
}

// appsettings.json configuration management example
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=NHibernateDemo;Integrated Security=true;TrustServerCertificate=true"
  },
  "NHibernate": {
    "ShowSql": true,
    "FormatSql": true,
    "CacheEnabled": true,
    "BatchSize": 20
  }
}

Basic CRUD Operations and Session Management

// Services/UserService.cs
using NHibernate;
using NHibernateDemo.Configuration;
using NHibernateDemo.Domain;

namespace NHibernateDemo.Services
{
    public class UserService
    {
        // Create - User creation
        public int CreateUser(User user)
        {
            using (var session = NHibernateHelper.OpenSession())
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    user.CreatedAt = DateTime.Now;
                    var id = (int)session.Save(user);
                    transaction.Commit();
                    return id;
                }
                catch
                {
                    transaction.Rollback();
                    throw;
                }
            }
        }

        // Read - User retrieval
        public User GetUser(int id)
        {
            using (var session = NHibernateHelper.OpenSession())
            {
                return session.Get<User>(id);
            }
        }

        public User GetUserByUsername(string username)
        {
            using (var session = NHibernateHelper.OpenSession())
            {
                return session.Query<User>()
                    .FirstOrDefault(u => u.Username == username);
            }
        }

        public IList<User> GetActiveUsers()
        {
            using (var session = NHibernateHelper.OpenSession())
            {
                return session.Query<User>()
                    .Where(u => u.IsActive)
                    .OrderBy(u => u.Username)
                    .ToList();
            }
        }

        // Update - User update
        public void UpdateUser(User user)
        {
            using (var session = NHibernateHelper.OpenSession())
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    session.Update(user);
                    transaction.Commit();
                }
                catch
                {
                    transaction.Rollback();
                    throw;
                }
            }
        }

        // Delete - User deletion
        public void DeleteUser(int id)
        {
            using (var session = NHibernateHelper.OpenSession())
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    var user = session.Get<User>(id);
                    if (user != null)
                    {
                        session.Delete(user);
                    }
                    transaction.Commit();
                }
                catch
                {
                    transaction.Rollback();
                    throw;
                }
            }
        }

        // Complex query example
        public IList<User> SearchUsers(string searchTerm, bool includeInactive = false)
        {
            using (var session = NHibernateHelper.OpenSession())
            {
                var query = session.Query<User>()
                    .Where(u => u.Username.Contains(searchTerm) ||
                               u.Email.Contains(searchTerm) ||
                               u.FirstName.Contains(searchTerm) ||
                               u.LastName.Contains(searchTerm));

                if (!includeInactive)
                {
                    query = query.Where(u => u.IsActive);
                }

                return query.OrderBy(u => u.Username).ToList();
            }
        }
    }
}

Advanced Queries with HQL and Criteria API

// Services/PostService.cs
using NHibernate;
using NHibernate.Criterion;
using NHibernateDemo.Configuration;
using NHibernateDemo.Domain;

namespace NHibernateDemo.Services
{
    public class PostService
    {
        // Queries using HQL (Hibernate Query Language)
        public IList<Post> GetPostsByAuthorHQL(string username)
        {
            using (var session = NHibernateHelper.OpenSession())
            {
                var hql = @"
                    FROM Post p 
                    INNER JOIN FETCH p.Author a
                    WHERE a.Username = :username 
                    AND p.Published = true
                    ORDER BY p.CreatedAt DESC";

                return session.CreateQuery(hql)
                    .SetParameter("username", username)
                    .List<Post>();
            }
        }

        // Named queries (defined in mapping files)
        public IList<Post> GetRecentPosts(int days)
        {
            using (var session = NHibernateHelper.OpenSession())
            {
                return session.GetNamedQuery("GetRecentPosts")
                    .SetParameter("days", days)
                    .List<Post>();
            }
        }

        // Dynamic queries using Criteria API
        public IList<Post> SearchPosts(string title = null, string authorName = null, 
            DateTime? fromDate = null, DateTime? toDate = null, bool? published = null)
        {
            using (var session = NHibernateHelper.OpenSession())
            {
                var criteria = session.CreateCriteria<Post>("p")
                    .CreateAlias("p.Author", "a");

                // Add dynamic conditions
                if (!string.IsNullOrEmpty(title))
                {
                    criteria.Add(Restrictions.Like("p.Title", title, MatchMode.Anywhere));
                }

                if (!string.IsNullOrEmpty(authorName))
                {
                    criteria.Add(Restrictions.Like("a.Username", authorName, MatchMode.Anywhere));
                }

                if (fromDate.HasValue)
                {
                    criteria.Add(Restrictions.Ge("p.CreatedAt", fromDate.Value));
                }

                if (toDate.HasValue)
                {
                    criteria.Add(Restrictions.Le("p.CreatedAt", toDate.Value));
                }

                if (published.HasValue)
                {
                    criteria.Add(Restrictions.Eq("p.Published", published.Value));
                }

                return criteria
                    .AddOrder(Order.Desc("p.CreatedAt"))
                    .List<Post>();
            }
        }

        // Paginated queries
        public IList<Post> GetPostsPaged(int pageNumber, int pageSize)
        {
            using (var session = NHibernateHelper.OpenSession())
            {
                return session.Query<Post>()
                    .Where(p => p.Published)
                    .OrderByDescending(p => p.CreatedAt)
                    .Skip((pageNumber - 1) * pageSize)
                    .Take(pageSize)
                    .ToList();
            }
        }

        // Statistical queries
        public object GetPostStatistics()
        {
            using (var session = NHibernateHelper.OpenSession())
            {
                var hql = @"
                    SELECT 
                        COUNT(*) as TotalPosts,
                        COUNT(CASE WHEN p.Published = true THEN 1 END) as PublishedPosts,
                        AVG(SIZE(p.Comments)) as AvgCommentsPerPost,
                        MAX(p.CreatedAt) as LatestPostDate
                    FROM Post p";

                return session.CreateQuery(hql).UniqueResult();
            }
        }
    }
}

Mapping with Fluent NHibernate

// Mappings/UserMap.cs
using FluentNHibernate.Mapping;
using NHibernateDemo.Domain;

namespace NHibernateDemo.Mappings
{
    public class UserMap : ClassMap<User>
    {
        public UserMap()
        {
            Table("Users");
            
            // Primary Key
            Id(x => x.Id, "UserId").GeneratedBy.Identity();
            
            // Properties
            Map(x => x.Username).Column("Username").Length(50).Not.Nullable().Unique();
            Map(x => x.Email).Column("Email").Length(255).Not.Nullable().Unique();
            Map(x => x.FirstName).Column("FirstName").Length(50);
            Map(x => x.LastName).Column("LastName").Length(50);
            Map(x => x.CreatedAt).Column("CreatedAt").Not.Nullable();
            Map(x => x.IsActive).Column("IsActive").Not.Nullable();
            
            // Relationships
            HasMany(x => x.Posts)
                .KeyColumn("AuthorId")
                .Cascade.AllDeleteOrphan()
                .Inverse()
                .LazyLoad();
        }
    }
    
    public class PostMap : ClassMap<Post>
    {
        public PostMap()
        {
            Table("Posts");
            
            Id(x => x.Id, "PostId").GeneratedBy.Identity();
            
            Map(x => x.Title).Column("Title").Length(200).Not.Nullable();
            Map(x => x.Content).Column("Content").CustomType("StringClob");
            Map(x => x.CreatedAt).Column("CreatedAt").Not.Nullable();
            Map(x => x.UpdatedAt).Column("UpdatedAt");
            Map(x => x.Published).Column("Published").Not.Nullable();
            
            References(x => x.Author)
                .Column("AuthorId")
                .Not.Nullable()
                .LazyLoad();
                
            HasMany(x => x.Comments)
                .KeyColumn("PostId")
                .Cascade.AllDeleteOrphan()
                .Inverse()
                .LazyLoad();
        }
    }
}

// Configuration/FluentNHibernateHelper.cs
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;

namespace NHibernateDemo.Configuration
{
    public static class FluentNHibernateHelper
    {
        private static ISessionFactory _sessionFactory;

        public static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    _sessionFactory = CreateSessionFactory();
                }
                return _sessionFactory;
            }
        }

        private static ISessionFactory CreateSessionFactory()
        {
            return Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2012
                    .ConnectionString("Server=localhost;Database=NHibernateDemo;Integrated Security=true;TrustServerCertificate=true")
                    .ShowSql()
                    .FormatSql())
                .Mappings(m => m.FluentMappings.AddFromAssemblyOf<UserMap>())
                .Cache(c => c
                    .UseSecondLevelCache()
                    .ProviderClass<NHibernate.Cache.HashtableCacheProvider>()
                    .UseQueryCache())
                .BuildSessionFactory();
        }

        public static ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }
    }
}

Transactions and Batch Processing

// Services/BatchService.cs
using NHibernate;
using NHibernateDemo.Configuration;
using NHibernateDemo.Domain;

namespace NHibernateDemo.Services
{
    public class BatchService
    {
        // Batch insert processing
        public void BulkInsertUsers(IEnumerable<User> users)
        {
            using (var session = NHibernateHelper.OpenSession())
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    int count = 0;
                    foreach (var user in users)
                    {
                        user.CreatedAt = DateTime.Now;
                        session.Save(user);
                        
                        // Flush every batch size
                        if (++count % 20 == 0)
                        {
                            session.Flush();
                            session.Clear();
                        }
                    }
                    
                    transaction.Commit();
                }
                catch
                {
                    transaction.Rollback();
                    throw;
                }
            }
        }

        // Batch update processing
        public int BulkUpdateUserStatus(bool isActive, DateTime beforeDate)
        {
            using (var session = NHibernateHelper.OpenSession())
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    var hql = @"
                        UPDATE User u 
                        SET u.IsActive = :isActive 
                        WHERE u.CreatedAt < :beforeDate";

                    var result = session.CreateQuery(hql)
                        .SetParameter("isActive", isActive)
                        .SetParameter("beforeDate", beforeDate)
                        .ExecuteUpdate();

                    transaction.Commit();
                    return result;
                }
                catch
                {
                    transaction.Rollback();
                    throw;
                }
            }
        }

        // Complex transaction processing
        public void TransferPostOwnership(int fromUserId, int toUserId)
        {
            using (var session = NHibernateHelper.OpenSession())
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    var fromUser = session.Get<User>(fromUserId);
                    var toUser = session.Get<User>(toUserId);
                    
                    if (fromUser == null || toUser == null)
                    {
                        throw new ArgumentException("Invalid user ID");
                    }

                    // Change post ownership
                    var posts = session.Query<Post>()
                        .Where(p => p.Author.Id == fromUserId)
                        .ToList();

                    foreach (var post in posts)
                    {
                        post.Author = toUser;
                        session.Update(post);
                    }

                    // Log recording
                    var log = new SystemLog
                    {
                        Message = $"Transferred {posts.Count} posts from user {fromUserId} to {toUserId}",
                        CreatedAt = DateTime.Now
                    };
                    session.Save(log);

                    transaction.Commit();
                }
                catch
                {
                    transaction.Rollback();
                    throw;
                }
            }
        }
    }
}