NHibernate – auto mapper

    • .NET
    • C#
    • XML
    • NHibernate
    • TDD
    • ORM
    • FluentNHibernate
  • modified:
  • reading: 3 minutes

В продолжение темы про NHibernate: xorets сделал мне дельное замечание по поводу того, что неуместно наследоваться от класса Configuration без необходимости: а сделал я это не просто так, а потому что была у нас задача создавать маппинг наших объектов в NHibernate при помощи наших собственных методанных, а так как некоторые необходимые методы были protected в классе Configuration мне и пришлось от него унаследоваться (пример, кстати, я взял откуда то). Хотел вам рассказать как реализовать автоматический маппинг, но вспомнил про FluentnHibernate и остановился. Это в нашем случае он не подходил, так как у нас были свои метаданные, а в обычном случае метаданными могут являться сами типы объектов и при помощи reflection можно получить достаточную информацию, чтобы замапить тип на таблицу, такое и предоставляет FluentnHibernate - Auto mapping. Вообще, если вы все же столкнетесь с такой задачей, как автоматический маппинг из своих методанных – то рекомендую не терять время на разбор кода NHibernate, а делать следующее – создавать по методанным обычные xml маппинги NHibernate и их уже подсовывать конфигурации (Так собственно и работают Fluent и ActiveRecord, если я ничего не путаю). Синтаксис xml маппинга и все подводные камни уже хорошо везде описаны, потому я и считаю это лучшим способом.

В случае, если вы будете использовать FluentnHibernate для автоматического маппинга типов на таблицы, расскажу как это легко настраивается.

Берем класс User:

namespace FluentnHibernateTest.Domain
{
    public class User
    {
        public virtual int Id { get; private set; }
        public virtual string Name { get; set; }
        public virtual string Surname { get; set; }
    }
}

Создаем для него таблицу в БД:

CREATE TABLE [User](
    [Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
    [Name] [varchar](50) NOT NULL,
    [Surname] [varchar](50) NOT NULL
 )

И последний рывок, пишем один класс – тест:

[TestFixture]
public class FluentTest
{
    private ISessionFactory _sessionFactory;
    private FluentConfiguration _configuration;
 
    [TestFixtureSetUp]
    public void SetUp()
    {
        _configuration = Fluently.Configure()
            .Database(MsSqlConfiguration.MsSql2008.ConnectionString("user id=XXX; password=XXX; server=(local); database=XXX;"))
            .Mappings(m => m.AutoMappings
                          .Add(AutoMap.AssemblyOf<User>().Where(t => t.Namespace == "FluentnHibernateTest.Domain")));
 
        _sessionFactory = _configuration.BuildSessionFactory();
    }
 
    [Test]
    public void TestData()
    {
       using (ISession session =  _sessionFactory.OpenSession())
       {
           User user = new User { Name = "User1_Name", Surname = "User1_Surname"};
           session.Save(user);
           session.Flush();
       }
 
       IList<User> users;
       using (ISession session = _sessionFactory.OpenSession())
       {
           users = session.CreateCriteria<User>()
               .Add(Restrictions.Eq("Name", "User1_Name"))
               .List<User>();
       }
 
       Assert.AreEqual(users.Count, 1);
       Assert.AreEqual(users[0].Surname, "User1_Surname");
 
       using (ISession session = _sessionFactory.OpenSession())
       {
           session.Delete(users[0]);
           session.Flush();
       }
    }
}

Как видно из кода я в методе SetUp законфигурировал NHibernate при помощи Fluently, указав просто, чтобы собралась информация по всем классам в сборке, в которой лежит тип User, и которые лежат в пространстве имен FluentnHibernateTest.Domain. Дальше код для тестирования работы самого ORM – он действительно работает :) Хотя конечно не так все гладко, за 10 секунд я не понял как сделать каскадное сохранение объектов, может такие случаи нужно самому добавлять? Не знаю…

В общем, напрашивается вывод. Если вы пишите приложение, на первом этапе которого уж очень простая логика, но есть опаска, что логика будет разрастаться, то наш вариант FluentnHibernate. При помощи которого изначально мы создадим автоматический маппинг, а дальше по мере необходимости будем его подпиливать. Интересно, живут ли такие проекты в настоящей жизни?

UPDATE: Вариантов автоматического маппинга много, иногда хватает и такого: Simple SQL Server Script For Generating NHibernate Classes/Mappings

See Also