- “Hello World” с использование NHibernate
- Разбираемся с архитектурой
- Написание и мэппинг (mapping) простой сущности (entity)
- Конфигурирование NHibernate
- Простые CRUD-операции
Для того, чтобы понять object/relational mapping, рассмотрим его на примере простого приложения, работающего с объектами БД.
1. Установка NHibernate
Скачать NHibernate можно с официального сайта в виде архива. В данном цикле статей, я буду использовать NHibernate 2.1.2.GA.
2. Проект в Visual Studio
Для начала создаем пустой бланк нового решения. Я назвал его “Hello NHibernate!” (неожиданно
).
Добавим в решение проект консольное приложение с именем “HelloNHibernate”.
В папке решения “Hello NHibernate!”, я рекомендую создать подпапку Libs для хранения библиотек, которые понадобятся в процессе работы. В этот каталог мы извлекаем и содержимое скачанного ранее архива NHibernate:
-
Required Bins
-
Required For LazyLoading
-
Tests
Теперь добавляем в References (Ссылки) NHibernate.dll. В классе Program.cs так же прописываем using NHibernate, using System.Reflection и NHibernate.Cfg.
1
2
3
4
5
6
7
8
9
10
11
12
13
14 using System;
using NHibernate;
using System.Reflection;
using NHibernate.Cfg;
namespace HelloNHibernate
{
class Program
{
static void Main(string[] args)
{
}
}
}
3. Класс “Служащий” (Employee).
Цель приложения – работа с записями таблицы Employee, хранящей информацию о служащих фирмы. Следовательно, добавляем в проект новый класс и называем его соответственно таблице — “Employee”. Код класса:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 using System;
namespace HelloNHibernate
{
class Employee
{
public int id;
public string name;
public Employee manager;
public string SayHello()
{
return string.Format("'Hello World!', said {0}.", name);
}
}
}
Как видите, класс имеет три поля: идентификатор, имя служащего, ссылку на объект класса и метод, возвращающий строку типа “’Hello World!’, said Andrey”. Для читателей, имеющих опыт работы с NHibernate, оговорюсь заранее, свойства затрону позже, пока ограничимся только паблик переменными.
Теперь используем описанный выше класс в приложении:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 using System;
using NHibernate;
using System.Reflection;
using NHibernate.Cfg;
namespace HelloNHibernate
{
class Program
{
static void Main(string[] args)
{
Employee anry = new Employee();
anry.name = "Andrey Krisanov";
Console.WriteLine(anry.SayHello());
Console.ReadKey();
}
}
}
4. База данных
Конечно же, БД! Именно она нужна нам для хранения и выполнения пр. операций с данными в нашем проекте. В качестве СУБД я использую Microsoft SQL Server 2008 Express Edition, однако NHibernate легко уживается и с другими. Приступим…
Запускаем Microsoft SQL Server Management Studio, соединяемся с сервером БД, открываем новое окно запросов и пишем код для создания новой базы:
1
2 CREATE DATABASE HelloNHibernate
GO
Выполняем его. Результат:
![]()
Далее переключаемся на нашу БД и создаем таблицу Employee:
1
2
3
4
5
6
7 USE HelloNHibernate
GO
CREATE TABLE Employee (
id int identity PRIMARY KEY,
name varchar(50),
manager int )
GO
Результат:
![]()
В итоге, все необходимые каркасы для использования NHibernate мы создали.
5. Создание служащего и сохранение его в БД
Этот функционал описывают две функции: CreateEmployeeAndSaveToDatabase и OpenSession:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 static void CreateEmployeeAndSaveToDatabase()
{
Employee andrey = new Employee();
andrey.name = "Andrey Krisanov";
using (ISession session = OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
session.Save(andrey);
transaction.Commit();
}
Console.WriteLine("Saved Andrey to the databases");
}
}
static ISessionFactory factory;
static ISession OpenSession()
{
if (factory == null)
{
Configuration conf = new Configuration();
conf.AddAssembly(Assembly.GetCallingAssembly());
factory = conf.BuildSessionFactory();
}
return factory.OpenSession();
}
Функции реализуют интерфейсы NHibernate ISession, ITransaction. Так же имеется статическое поле factory, реализующее интерфейс ISessionFactory. Подробнее об этих интерфейсах расскажу позже. Пока достаточно знать, что SessionFactory создается один раз и используется на протяжении всей работы приложения, Session же можно создавать сколько угодно.
Если мы вызовем метод CreateEmployeeAndSaveToDatabase, NHibernate фактически выполнить SQL-запрос:
1
2 INSERT INTO Employees (name, manager)
VALUES ('Andrey Krisanov', NULL)
OpenSession () вызывается всегда, когда необходимо просматривать, сохранять, искать и выполнять прочие действия с объектами в базе данных. В ваших будущих production-проектах я не рекомендую использовать OpenSession, более экономичные способы опишу в следующих постах.
Итак, мы создали класс Служащий (Employee), добавили таблицу для его хранения в БД и написали некоторый код, для сохранения объекта с использованием NHibernate.
6. Загрузка служащих из базы данных
Получим список всех служащих, содержащихся в таблице и заставим сказать их “Привет мир!”.
Добавим код в Program.cs и не забудем подключить System.Collections.Generic для IList:
1
2
3
4
5
6
7
8
9
10
11 static void LoadEmployeesFromDatabase()
{
using (ISession session = OpenSession())
{
IQuery query = session.CreateQuery("from Employee as emp order by emp.name asc");
IList foundEmployees = query.List();
Console.WriteLine("\n{0} employees found:", foundEmployees.Count);
foreach (Employee employee in foundEmployees)
Console.WriteLine(employee.SayHello());
}
}
Литерал «from Employee as emp order by emp.name asc» – запрос NHibernate (HQL). Во время вызова query.List () он будет транслирован в SQL:
1
2
3 SELECT e.id, e.name, e.manager
FROM Employee e
ORDER BY e.name ASC
Есть и еще более простой способ получить все записи таблицы, но об этом снова позже
Подведем некоторые итоги. После прочтения вышеописанного материала у вас должно было сформироваться ощущение, что чего-то не хватает в структуре нашего проекта, какого-то связующего звена между Employee и NHibernate. Откуда берутся знания о классе для сохранения и извлечения соответствующих объектов? Отвечаю.
7. Создание файла мэппинга (mapping file)
Прежде, чем в полною меру использовать NHibernate, необходимо сообщить информацию о классе Employee. Сделать это можно несколькими способами. Для начала рассмотрим XML-файлы – базовый способ мэппинга.
Для IntelliSense закидываем в папку Microsoft Visual Studio\Xml\Schemas файлы схем NHibernate:
- nhibernate-configuration.xsd
- nhibernate-mapping.xsd
Затем добавляем в проект xml-файл, который называем Employee.hbm.xml, имя файла совпадает с именем класса + .hbm.xml.
В свойствах Employee.hbm.xml в Build Action (Действие при построении) выбираем “Embedded Resource” (Внедренный ресурс). Не пропустите данный шаг, иначе NHibernate не сможет найти нужную мэппинг информацию!
Теперь открываем Employee.hbm.xml и прописываем в нем:
1
2
3
4
5
6
7
8
9
10 <?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
<class name="HelloNHibernate.Employee, HelloNHibernate" lazy="false">
<id name="id" access="field">
<generator class="native" />
</id>
<property name="name" access="field" column="name"/>
<many-to-one access="field" name="manager" column="manager" cascade="all"/>
</class>
</hibernate-mapping>
При наборе кода, видим подсказки IntelliSense (не зря же мы копировали файлы схем в папку Студии).
Итак, в файле мэппинга мы сообщили информацию о классе Employee, в какие столбцы таблицы будут записываться данные его полей. Как видите, все довольно просто.
Осталось сконфигурировать NHibernate под наш проект.
8. Конфигурирование приложения
Если вы ранее работали с БД в .NET (использовали DataSet, DataReader и пр.), то знаете о необходимости прописывать ConnectionString в файле web.config или app.config. Для NHibernate ситуация аналогичная:
- Добавляем в проект конфигурационный файл.
- Определяем настройки:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 <?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="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>
<property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider
</property>
<property name="connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name="connection.connection_string">
Data Source=ANRY-NOTEBOOK\SQLEXPRESS;Initial Catalog=HelloNHibernate;Persist Security Info=True;User ID=test;Password=test
</property>
<property name="dialect">
NHibernate.Dialect.MsSql2005Dialect
</property>
<property name="show_sql">
false
</property>
</session-factory>
</hibernate-configuration>
</configuration>
NHibernate очень гибок, и вариантов конфигурации ORM под ваши нужды существуем достаточно много. Обратите внимание, свойство “connection.connection_string” содержит строку подключения к БД, используемой в проекте. При необходимости, замените ее на актуальную для вашего сервера.
9. Обновление записи служащего
Перед тем, как запустить и проверить работу нашего приложения, добавим в него еще одну функцию, которая обновит запись обо мне и добавить новую:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 static void UpdateAndreyAndAssignNikolayAsManager()
{
using (ISession session = OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
IQuery q = session.CreateQuery("from Employee where name = 'Andrey Krisanov'");
Employee andrey = q.List()[0];
andrey.name = "Andrey Anatolevich Krisanov";
Employee nikolay = new Employee();
nikolay.name = "Nikolay Evseev";
andrey.manager = nikolay;
transaction.Commit();
Console.WriteLine("Updated Andrey and added Nikolay Evseev!");
}
}
}
При выполнении метода NHibernate переведет описанный выше код в SQL:
1
2
3
4
5
6
7
8
9
10 SELECT e.id, e.name, e.manager
FROM Employee e
WHERE e.id = 1
INSERT INTO Employees (name, manager)
VALUES ('Nikolay Evseev', NULL)
declare @newId int
SELECT @newId = scope_identity()
UPDATE Employees
SET name = 'Andrey Anatolevich Krisanov', manager = @newId
WHERE id = 1
ORM рулит!
10. Запуск программы
Ключевой момент данного топика – проверка работы написанного кода. Модифицируем метод Main () класса Program.cs:
1
2
3
4
5
6
7
8 static void Main(string[] args)
{
CreateEmployeeAndSaveToDatabase();
UpdateAndreyAndAssignNikolayAsManager();
LoadEmployeesFromDatabase();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
Результат:
Записи в таблице:
P.S. Подключите к проекту следующие сборки:

