Часть 1 | Часть 2 | Часть 3 (автомэппинг)
Эта статья является продолжением и содержит материал, рассказанный на заседании MCP клуба 24 декабря 2009 года.
В прошлой части мы рассмотрели базовые возможности Fluent NHibernate, научились строить мэппинг. Теперь попробуем использовать все это для создания базы данных и сохранения/загрузки сущностей в базе.
Разобьем задачу на подзадачи:
- Создание конфигурации NHibernate (класс Configuration)
- Создание структуры базы
- Управление сессиями и транзакциями
- Управление сущностями (CRUD)
Итак, конфигурирование подключения мы рассматривали в прошлой части, здесь не будем заострять на этом внимание, повторю лишь код:
Config = Fluently.Configure(). Database( MsSqlConfiguration .MsSql2008 .ConnectionString(x => x .Server(@".\SQLEXPRESS") .Database("Orders") .TrustedConnection()) .UseReflectionOptimizer()) .Mappings(m => m.FluentMappings.AddFromAssemblyOf<ProductMap>()) .BuildConfiguration();
Структура базы
Для создания структуры базы в NHibernate существует класс-утилита SchemaExport.
new SchemaExport(Config).Create(true, true);
Выполнение метода Create приведет к созданию всех таблиц и связей между ними, согласно описанных мэппингов.
Управление сессиями и транзакциями
В мире NHibernate принято использовать сессии для манипулирования сущностями. Сессия представляет контекст подключения к базеданных и выполняет трекинг сущностей (отслеживает изменения свойств и тп.). Кроме того, сессии поддерживают транзакции. Для того, чтобы создать сессию, требуется сначала создать фабрику сесиий (на основе нашей конфигурации):
ISessionFactory factory = Config.BuildSessionFactory();
Теперь у нас есть возможность создавать сесиии:
ISession session = factory.OpenSession();
По окончании использования сесии мы сбрасываем ее состояние в базу (Flush) закрываем ее (Close).
В рамках сессий мы можем и должны использовать транзакции (вы же знаете, что это такое?):
using (ITransaction transaction = session.BeginTransaction()) { //... // действия над сущностями //... transaction.Commit(); //здесь мы сохраняем все в базу }
CRUD, шаблон IRepository, Generic DAO и все все все…
Последнее, что осталось сделать — это реализовать возможность сохранения и загрузки наших сущностей.
Для этого существует NHibernate Best practice рекомендация — использование Generic DAO.
В качестве частного случая использования этого шаблона рассмотрим реализацию репозитория:
public interface IRepository<T> { void Save(T item); T ReadById(Guid id); List<T> ReadAll(); void Delete(T item); }
Как видно, наш репозиторий будет generic-реализацией, это позволит использовать его для различного типа сущностей.
Метод Save в данном случае отвечает как за обновление существующей сущности в базе, так и за создание новой сущности.
Вот реализация репозитория:
public class EntityRepository<T> : IRepository<T> { private ISession session; public EntityRepository(ISession session) { this.session = session; } #region IRepository<T> Members public void Save(T item) { session.Save(item); } public List<T> ReadAll() { return new List<T>(session.CreateCriteria(typeof(T)).List<T>()); } public T ReadById(Guid id) { return session.Get<T>(id); } public void Delete(T item) { session.Delete(item); } #endregion }
Ну вот, теперь все готово, ниже приведу код для создания и сохранения конкретных экземпляров сущностей:
using (ITransaction transaction = session.BeginTransaction()) { List<Product> productList = new List<Product> { new Product { Name = "ACER Extensa 5220", ProductNumber = 1, Price = 400.0, Code = "acerEX5220" }, new Product { Name = "Acer Aspire One AO531h", ProductNumber = 2, Price = 500.0, Code = "aspireAO531" }, new Product { Name = "Acer Aspire One D250-0Bk", ProductNumber = 3, Price = 550.0, Code = "acerD250" }, new Product { Name = "D-Link DIR300 Wifi Router", ProductNumber = 4, Price = 90.0, Code = "dir300" }, }; List<Customer> customerList = new List<Customer> { new Customer { FirstName = "John", SecondName="Smith", Comment = "the matrix" }, new Customer { FirstName = "Ivan", SecondName="Ivanov", Comment = "Krasnoyarsk" }, new Customer { FirstName = "Igor", SecondName="Nikolaev", Comment = "the developer" }, }; Order order1 = new Order { Customer = customerList.Last(), Product = productList.First(), Date = DateTime.Now, OrderNumber = 1, Count = 1 }; IRepository<Product> products = new EntityRepository<Product>(session); productList.ForEach(products.Save); IRepository<Customer> customers = new EntityRepository<Customer>(session); customerList.ForEach(customers.Save); IRepository<Order> orders = new EntityRepository<Order>(session); orders.Save(order1); transaction.Commit(); }
Ну и код для загрузки этих сущностей:
IRepository<Product> products = new EntityRepository<Product>(session); products.ReadAll().ForEach(p => Console.WriteLine(p.Name)); Console.WriteLine(new String('=', 20)); IRepository<Customer> customers = new EntityRepository<Customer>(session); customers.ReadAll().ForEach(Console.WriteLine); Console.WriteLine(new String('=', 20)); IRepository<Order> orders = new EntityRepository<Order>(session); orders.ReadAll().ForEach(Console.WriteLine);
p.s. Для того, чтобы увидеть строковые представления, необходимо переопределить метод ToString()
Вот собственно и все, надеюсь, вам был интересен и полезен данный материал.
В ближайшее время мы рассмотрим возможности модульного тестирования Fluent NHibernate с использованием технологии NUnit.
Часть 1 | Часть 2 | Часть 3 (автомэппинг)