Часть 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 (автомэппинг)


