Быстрый старт с Fluent NHibernate. Часть 2

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

Рейтинг
( Пока оценок нет )
Загрузка ...