NHibernate для C# (.NET): полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое NHibernate и зачем он нужен?

NHibernate — это мощная и зрелая объектно-реляционная библиотека (ORM) для платформы .NET, написанная на C#. Она является портом знаменитой Java-библиотеки Hibernate. NHibernate решает фундаментальную проблему несоответствия между объектно-ориентированной моделью данных в вашем C#-приложении и реляционной моделью данных в базе данных (SQL Server, PostgreSQL, MySQL, Oracle и др.).

Основная задача NHibernate — автоматизировать преобразование данных между объектами C# (POCO — Plain Old CLR Objects) и записями в таблицах базы данных. Вместо того чтобы писать сотни строк однотипного SQL-кода для CRUD-операций (Create, Read, Update, Delete), вы работаете с объектами, а NHibernate берет на себя генерацию и выполнение SQL-запросов.

Зачем использовать NHibernate?

  • Повышение производительности разработки: Вы пишете меньше кода, особенно boilerplate-кода для работы с ADO.NET.
  • Уменьшение количества ошибок: SQL-запросы генерируются автоматически, что снижает риск синтаксических ошибок и SQL-инъекций (при правильном использовании).
  • Независимость от базы данных: Вы можете сменить СУБД, изменив только строку подключения и диалект NHibernate, не переписывая бизнес-логику.
  • Управление кэшированием: Встроенные механизмы кэширования первого и второго уровня значительно ускоряют работу приложения.
  • Lazy Loading (Отложенная загрузка): Связанные данные загружаются только тогда, когда они действительно нужны, что экономит ресурсы.
  • Мощный язык запросов: HQL (Hibernate Query Language) и LINQ to NHibernate позволяют писать типобезопасные запросы.

Установка NHibernate

NHibernate распространяется через NuGet — менеджер пакетов для .NET. Установка очень проста.

Через консоль диспетчера пакетов (Package Manager Console):

Install-Package NHibernate

Через .NET CLI (для проектов .NET Core / .NET 5+):

dotnet add package NHibernate

Дополнительные пакеты (по необходимости):

  • NHibernate.Caches.CoreMemoryCache — для кэширования второго уровня.
  • System.Data.SqlClient или Microsoft.Data.SqlClient — для работы с SQL Server.
  • Npgsql — для работы с PostgreSQL.
  • MySql.Data — для работы с MySQL.

После установки вам потребуется настроить конфигурацию (обычно в файле app.config, web.config или appsettings.json) или через Fluent-конфигурацию в коде.

Быстрый старт с примером кода

Рассмотрим простейший пример работы с NHibernate. Допустим, у нас есть таблица Products в базе данных SQL Server.

1. Создаем класс сущности (Entity):

public class Product
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual decimal Price { get; set; }
}

Важно: Все свойства должны быть virtual — это требование NHibernate для реализации механизмов прокси (lazy loading, отслеживание изменений).

2. Создаем файл маппинга (Product.hbm.xml):

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="YourAssemblyName"
                   namespace="YourNamespace">
    <class name="Product" table="Products">
        <id name="Id" column="ProductId">
            <generator class="native" />
        </id>
        <property name="Name" column="ProductName" length="100" not-null="true" />
        <property name="Price" column="UnitPrice" precision="19" scale="4" />
    </class>
</hibernate-mapping>

Этот XML-файл говорит NHibernate, как сопоставить класс Product с таблицей Products и её столбцами.

3. Настраиваем и используем NHibernate:

using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;

public class NhibernateHelper
{
    private static ISessionFactory _sessionFactory;

    public static ISessionFactory CreateSessionFactory()
    {
        if (_sessionFactory == null)
        {
            var configuration = new Configuration();
            configuration.Configure(); // Читает настройки из app.config/web.config
            configuration.AddAssembly(typeof(Product).Assembly); // Добавляет файлы .hbm.xml из сборки
            _sessionFactory = configuration.BuildSessionFactory();
        }
        return _sessionFactory;
    }

    public static void SaveProduct()
    {
        using (var session = CreateSessionFactory().OpenSession())
        using (var transaction = session.BeginTransaction())
        {
            var newProduct = new Product { Name = "Laptop", Price = 1200.00m };
            session.Save(newProduct);
            transaction.Commit();
            Console.WriteLine($"Product saved with ID: {newProduct.Id}");
        }
    }
}

4. Конфигурация в app.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
    </configSections>
    <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
        <session-factory>
            <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
            <property name="connection.connection_string">Server=.;Database=MyDB;Integrated Security=True;</property>
            <property name="dialect">NHibernate.Dialect.MsSql2012Dialect</property>
        </session-factory>
    </hibernate-configuration>
</configuration>

Основные методы и функции NHibernate

Ниже приведены ключевые методы, которые вы будете использовать ежедневно при работе с NHibernate.

1. session.Save(object entity)

Что делает: Сохраняет новый экземпляр сущности в базу данных. После вызова объект становится постоянным (persistent).

Параметры: entity — объект сущности, который нужно сохранить.

Пример:

var customer = new Customer { Name = "John Doe", Email = "john@example.com" };
var savedId = session.Save(customer);
Console.WriteLine($"Customer saved with ID: {savedId}");

2. session.Update(object entity)

Что делает: Обновляет существующую запись в базе данных, соответствующую переданному объекту. Объект должен быть detached (отсоединенным) или persistent.

Параметры: entity — объект с измененными данными.

Пример:

var product = session.Get<Product>(1); // Загружаем объект
product.Price = 1500.00m; // Меняем цену
session.Update(product); // Явно обновляем (можно не вызывать, если сессия открыта)
session.Flush(); // Принудительно синхронизируем с БД

3. session.Delete(object entity)

Что делает: Удаляет запись из базы данных, соответствующую переданному объекту.

Параметры: entity — объект, который нужно удалить.

Пример:

var order = session.Get<Order>(42);
session.Delete(order);
session.Flush();

4. session.Get<T>(object id)

Что делает: Загружает сущность по её первичному ключу. Если запись не найдена, возвращает null. Использует кэш первого уровня.

Параметры: id — значение первичного ключа.

Пример:

var user = session.Get<User>(5);
if (user != null)
{
    Console.WriteLine($"User: {user.Username}");
}

5. session.Load<T>(object id)

Что делает: Возвращает прокси-объект для сущности с указанным ID. Реальный запрос к БД не выполняется до первого обращения к свойству, отличному от ID. Если записи не существует, выбросит исключение ObjectNotFoundException при попытке доступа.

Параметры: id — значение первичного ключа.

Пример:

// Получаем прокси, запрос к БД еще не сделан
var categoryProxy = session.Load<Category>(10);
// Только здесь выполняется SELECT
Console.WriteLine($"Category name: {categoryProxy.Name}");

6. session.CreateQuery(string hql)

Что делает: Создает запрос на языке HQL (Hibernate Query Language), который затем можно выполнить. HQL похож на SQL, но оперирует именами классов и свойств, а не таблиц и столбцов.

Параметры: hql — строка HQL-запроса.

Пример:

IQuery query = session.CreateQuery("from Product p where p.Price > :minPrice");
query.SetParameter("minPrice", 100.00m);
IList<Product> expensiveProducts = query.List<Product>();
foreach (var p in expensiveProducts)
{
    Console.WriteLine($"{p.Name} - {p.Price}");
}

7. session.Query<T>() (LINQ to NHibernate)

Что делает: Предоставляет возможность писать типобезопасные LINQ-запросы. Это наиболее предпочтительный способ запросов в современном C#.

Параметры: Нет (возвращает IQueryable<T>).

Пример:

var recentOrders = session.Query<Order>()
    .Where(o => o.OrderDate >= DateTime.Now.AddDays(-7))
    .OrderByDescending(o => o.TotalAmount)
    .Take(10)
    .ToList();

8. session.CreateCriteria<T>()

Что делает: Создает объект Criteria, который позволяет программно строить запросы. Полезен для динамических запросов.

Параметры: Нет (возвращает ICriteria).

Пример:

var criteria = session.CreateCriteria<Employee>()
    .Add(Restrictions.Like("Name", "Smith%"))
    .Add(Restrictions.Gt("Salary", 50000))
    .AddOrder(Order.Asc("Name"));
IList<Employee> employees = criteria.List<Employee>();

9. session.BeginTransaction()

Что делает: Начинает новую транзакцию базы данных. Все изменения, сделанные после вызова этого метода, будут либо зафиксированы (Commit), либо отменены (Rollback).

Параметры: Нет (возвращает ITransaction).

Пример:

using (var transaction = session.BeginTransaction())
{
    try
    {
        session.Save(new Invoice { Number = "INV-001" });
        session.Save(new Payment { Amount = 100 });
        transaction                    

Рекомендаций