Основы NHibernate. Часть 1

    Не так давно попался под руки новый проект. До сих пор, в основном, приходилось допиливать старые. В проекте предполагалось использование БД. Погуглив немного решил отказаться от старых методов работы с данными в пользу ORM. Да, есть много кодогенераторов(например, CodeSmith), которые в считанные секунды создадут уровень доступа к данным, но такие решения не отличаются гибкостью, а при дальнейшем развитии грозят превратиться в кошмар. Хотя и у ORM тоже есть свои недостатки. Но обо всем по порядку. Сейчас же я хочу поделиться с вами моим опытом в освоении одного из представителей мира ORM — NHibernate. Почему из всех возможных ORM я выбрал для изучения NHibernate? Во-первых, потому что надо было выбрать что-то одно. Во-вторых, история NHibernate уходит глубоко корнями в ORM-фреймвокр Hibernate для Java и является достаточно зрелым решением. Больше пока, вроде, и нет аргументов, но, думаю, они появятся позже при более близком знакомстве с NHibernate.

    Главная задача ORM(Object-Relational Mapping) заключается в том, чтобы являться тем связующим звеном, которое прозрачно для нас будет делать всю работу по сохранению данных наших бизнес-объектов и заполнению их даными из базы при необходимости. К тому же ORM избавляет от необходимости большого количества однотипного примитивного кода выполняющего всего лишь CRUD-операции(Create, Read, Update, Delete). Это конечно самое простое объяснение смысла ORM, но думаю идея ясна. Больше можно прочитать здесь.

    Прежде чем начать работать нам необходима сама библиотека. Пока будет идти речь о версии 1.2.1, если не будет указано обратное. Совсем недавно вышла вторая версия фреймворка в которой обещали много вкусностей, но опять же не будем торопить события ;). Архив со всем необходимым можно скачать здесь. Распаковав архив, вы увидите множество файлов, но на первых порах не все они нам будут нужны. Самым главным и необходимым для нас файлом будет NHibernate.dll. Это пока единственная библиотека, референс на которую нужно добавлять в проект. Также необходимы будут Iesi.Collections.dll, Castle.DynamicProxy.dll и log4net.dll, но их нет нужды добавлять, NHibernate.dll сам их подгрузит
    при необходимости.

    Для понимания основ NHibernate мы создадим простенький класс, сконфигурируем наше приложение и попробуем создать экземпляр класса, сохранить его в базе и достать его обратно.

    Первым делом создадим простой класс Book:

    1. public class Book
    2. {
    3.   private long id;
    4.   private string isbn;
    5.   private string title;
    6.  
    7.   public virtual long ID
    8.   {
    9.     get { return id; }
    10.     protected set { id = value; }
    11.   }
    12.  
    13.   public virtual string ISBN
    14.   {
    15.     get { return isbn; }
    16.     set { isbn = value; }
    17.   }
    18.  
    19.   public virtual string Title
    20.   {
    21.     get { return title; }
    22.     set { title = value; }
    23.   }
    24.  
    25.   public Book()
    26.   {
    27.   }
    28.  
    29.   public Book(string bookIsbn, string bookTitle)
    30.   {
    31.     isbn = bookIsbn;
    32.     title = bookTitle;
    33.   }
    34. }
    * This source code was highlighted with Source Code Highlighter.



    Сразу отмечу особенность NHibernate: он не требует никаких дополнительных усилий по реализации специфического интерфейса или наследования от базового класса. Т.е. вы можете описывая объекты бизнес-логики не задумываться о реализации каких бы то ни было механизмов для взаимодействия с БД. Всю грязную работу на себя возьмет NHibernate. Но каким бы он ни был всемогущим, ему все равно надо брать откуда то информацию о классах, их полях и свойствах. Есть два способа предоставить эту информацию. Первый — описать всю необходимую информацию в атрибутах класса, его полей и свойств, второй — задать все необходимые соответствия между классом, его данными и таблицей в БД в mapping-файле. Считаю второй способ более удобным и наглядным(отделим мух от котлет ;)).

    о_О Знаю, что это субъективное мнение, но мне так проще. К тому же есть инструменты облегчающие и автоматизирующие это.
    О них будет рассказано в продолжении серии.

    При написании или правки мэппинга вручную совсем не хочется обращаться каждый раз к справочнику, чтобы вспомнить нужный атрибут или элемент. В этом нам поможет VS и xsd-схемы для конфигурационного и мэппинг файлов. Они находятся в скачанном ранее архиве. Это nhibernate-configuration-2.0.xsd, nhibernate-mapping-2.0.xsd и nhibernate-generic.xsd. Копируем их в папку [Path To Microsoft Visual Studio Folder]\Xml\Schemas и перезапускаем студию. Всё, можно пользоваться Intellisense при создании mapping-файлов.


    Mapping-файл может выглядеть примерно так:
    1. <?xml version="1.0" encoding="utf-8" ?>
    2. <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="NHibernate_1" assembly="NHibernate_1">
    3.  <class name="Book" table="Books">
    4.   <id name="ID" unsaved-value="0">
    5.    <column name="ID" not-null="true" />
    6.     <generator class="identity"/>
    7.   </id>
    8.   <property name="ISBN" />
    9.   <property name="Title" />
    10.  </class>
    11. </hibernate-mapping>
    * This source code was highlighted with Source Code Highlighter.



    1. <class name="Book" table="Books">

    Здесь мы описываем класс который мапим и таблицу в БД в которой будут хранится данные.

    1. <id name="ID" unsaved-value="0">
    2.  <column name="ID" not-null="true" />
    3.   <generator class="identity"/>
    4. </id>

    Здесь задается идентификатор. В качестве генератора идентификатора используется класс Identity, который есть в SQL Serrver-е. Можно использовать некоторые другие генераторы, а также написать самому класс, реализующий интерфейс NHibernate.Id.IIdentifierGenerator.

    1. <property name=«ISBN» />
    2. <property name=«Title» />

    Ну и здесь описываются все остальные свойства нашего класса.

    Для начала этого, думаю, будет достаточно. Подробнее о mapping-файлах будет рассказано позже. По сложившейся традиции файлу дают название Имя_класса.hbm.xml, но это не является обязательным требованием. Далее не забудьте указать в свойствах этого xml файла Build Action = Embedded Resource для того, чтоб файл был включен в финальную сборку.

    Следующим шагом будет подключение к БД, где мы и будем хранить даные. Нам необходимо создать файл настроек для NHibernate. В нашем первом примере он будет предельно простым, но все же достаточным для того, чтоб можно было полноценно работать с БД.

    Выглядит он следующим образом:
    1. <?xml version='1.0' encoding='utf-8'?>
    2. <hibernate-configuration>
    3.    
    4.    <session-factory xmlns="urn:nhibernate-configuration-2.2">
    5.       
    6.       <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    7.       <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
    8.       <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
    9.       <property name="connection.connection_string">Server=DevDB;Initial Catalog=NHibTut;Trusted_Connection=yes;</property>
    10.  
    11.       <mapping resource="NHibernate_1.Book.hbm.xml" assembly="NHibernate_1" />
    12.  
    13.    </session-factory>
    14.    
    15. </hibernate-configuration>
    * This source code was highlighted with Source Code Highlighter.


    1. <session-factory xmlns="urn:nhibernate-configuration-2.2">

    Обязательный элемент. Здесь находятся все настройки для объекта класса ISessionFactory.

    connection.provider — Провайдер для подключения к базе. Должен реализовывать интерфейс IConnectionProvider. В нашем случае используется родной провайдер.

    connection.driver_class — Класс реализующий IDriver. В нашем случае используется встроенный драйвер для подключения к MS SQL Server.

    dialect — Реализация диалекта для конкретного сервера БД. В нашем случае используется NHibernate.Dialect.MsSql2005Dialect, так как мы используем MS SQL Server 2005 Express Edition.

    connection.connection_string — Строка подключения к БД.

    Здесь хочу сделать небольшое уточнение. Так как зачастую приходится работать на разных компьютерах, то для того чтоб постоянно не менять строку подключения к БД, можно создать псевдоним(alias) для вашей базы. Таким образом вам больше не надо будет беспокоиться о строке подключения откуда бы вы ни работали.


    1. <mapping resource="NHibernate_1.Book.hbm.xml" assembly="NHibernate_1" />

    Здесь мы указываем mapping-файл нашего класса и сборку, в которой его можно найти.

    Следующим шагом будет конфигурирование самого NHibernate. За это отвечает класс Configuration.
    1. ISessionFactory sessionFactory = new Configuration().Configure("Nhibernate.cfg.xml").BuildSessionFactory();


    Можно и не задавать название файла конфигурации «Nhibernate.cfg.xml», тогда он должен называться «hibernate.cfg.xml», потому что именно файл с таким названием ищет в корневом каталоге NHibernate. В приведенном выше примере мы сконфигурировали NHibernate и на основе даной конфигурации создали фабрику сессий ISessionFactory.

    ISessionFactory — интерфейс служащий фабрикой по созданию ISession непосредственно для работы с БД. Создание ISessionFactory ресурсоемкий процесс и предполагается использованние его единственного экземпляра из любых частей приложения, так как является потокобезопасным. Если из вашего приложения есть необходимость подключения к нескольким БД, то для каждой из них нужно создавать отдельный ISessionFactory. ISessionFactory также кэширует SQL запросы к базе, может хранить кэшированные данные, которые были запрошены из базы.

    Для выполнения любого действия связанного с БД, будь то запрос, сохранение, редактирование объекта, нам не обойтись без ISession. Это легковесный интерфейс и его создание требует совсем немного ресурсов. Разработчики NHibernate советуют создавать его каждый раз при обращении к базе. Для примера в ASP.NET приложении можно создавать экземпляр ISession на каждый HttpRequest. ISession не является потокобезопасным, поэтому необходимо его использовать в одном потоке. ISession является реализацией разработчиками NHibernate паттерна Unit of Work.

    Unit of Work содержит список объектов, отслеживает их изменения, а затем записывает изменения в базу.

    UnitofWork отслеживает все изменения, так как является единственным способом доступа к базе.
    Объекты, не помещенные в UnitOfWork, не будут записаны в базу, т.е. при использовании данного шаблона нельзя обращаться к базе напрямую.

    Алгоритм работы с Unit of Work в общем случае такой:

    1. Объект считывается из базы и регистрируется в списке Unit of Work.
    Сразу после считывания из базы объект помечается как «чистый», т.е. Dirty = false;
    2. При изменении или при создании объект помечается как Dirty = true
    3. При удалении как Deleted
    4. Для записи изменений в базу вызывается Commit


    Для упрощения работы с ISessionFactory и ISession мы создадим класс Domain. Здесь я не буду приводить весь текст класса,
    а только метод получения сессии:
    1. private static ISession GetSession(bool getNewIfNotExists)
    2. {            
    3.    ISession currentSession;
    4.  
    5.    if (HttpContext.Current != null)
    6.    {
    7.       HttpContext context = HttpContext.Current;
    8.       currentSession = context.Items[sessionKey] as ISession;
    9.  
    10.       if (currentSession == null && getNewIfNotExists)
    11.       {
    12.          currentSession = sessionFactory.OpenSession();
    13.          context.Items[sessionKey] = currentSession;
    14.       }
    15.    }
    16.    else
    17.    {
    18.       currentSession = CallContext.GetData(sessionKey) as ISession;
    19.  
    20.       if (currentSession == null && getNewIfNotExists)
    21.       {
    22.          currentSession = sessionFactory.OpenSession();
    23.          CallContext.SetData(sessionKey, currentSession);
    24.       }
    25.    }
    26.  
    27.    return currentSession;
    28. }
    * This source code was highlighted with Source Code Highlighter.



    В зависимости от того работаем мы с БД из web- или win-приложения сессия сохраняется/извлекается в/из
    HttpContext.Current.Items и CallContext соответственно. Конечно сам класс Domain далек от идеала и мне там не все нравится, но пока ничего лучшего не придумал. Буду рад советам. :)

    Итак мы закончили поготовку простой и минимально необходимой инфрасткутуры для нашего не менее простого примера демонтрации работы NHibernate:
    1. class Program
    2. {
    3.    static void Main()
    4.    {
    5.       // Инициваллизация домена
    6.       Domain.Init();
    7.       
    8.       // Идентификатор объекта Book
    9.       long bookId;
    10.       
    11.       // достаем сессию
    12.       ISession session = Domain.CurrentSession;
    13.       
    14.       // Начинаем явную транзакцию
    15.       ITransaction tr = session.BeginTransaction();
    16.  
    17.       // Создаем экземпляр класса Book
    18.       Book book = new Book("NW8523IDISDN", "How to learn not to do stupid things v.1");
    19.                
    20.       // Сохрананяем объект в сессии
    21.       session.Save(book);
    22.       
    23.       // Запоминаем идентификатор объекта
    24.       bookId = book.ID;
    25.       
    26.       // Завершаем транзакцию. Сейчас данные будут физически записаны в БД
    27.       // После этого можно отрыть таблицу в БД и убедиться, что там действительно появилаь новая запись
    28.       tr.Commit();
    29.       session.Flush();
    30.  
    31.       // Очищаем кэш сессии, чтобы быть уверенными, что объект будет получен из базы, а не из сессии
    32.       session.Clear();
    33.       
    34.       // Пытаемся достать объект из базы по идентификатору
    35.       Book book1 = session.Get<Book>(bookId);
    36.  
    37.       // Сравниваем и видим, что объект который мы сохранили и тот который мы достали из сессии один и тот же
    38.       if (book == book1) { Console.WriteLine("Yep!!!"); }
    39.  
    40.       // Завершаем работу с базой.
    41.       Domain.Close();
    42.       Console.ReadKey();
    43.    }
    44. }
    * This source code was highlighted with Source Code Highlighter.



    Надеюсь, код с комментариями предельно ясен. Я намеренно не стал приводить здесь примеры посложнее. Эту первую статью я постарался сделать как можно проще, чтобы создать базу для последующих, в которых будет (я очень надеюсь ;)) более глубокое содержание материала.

    Исходники проекта можно скачать здесь.

    UPD: Совсем забыл :-[, хочу выразить отдельную благодарность XaocCPS за помощь в редактировании статьи.
    Share post

    Similar posts

    Comments 66

      +1
      Спасибо, попробуем.
        –4
        +1
          0
          Очень интересно было бы услышать, про генерацию скрипта для создания структуры БД. Ну и вдвойне интересней с примерами генерации под разные СУБД.
            0
            Это скорее всего будет во 2-й или 3-й части. :)
            +2
            if (book == book1) { Console.WriteLine(«Yep!!!»); }
            чтобы так делать, нужно в классе Book перегрузить оператор ==.
              0
              да, вы правы. недочетик ;) я вообще там ID хотел сравнить. будем исправляться.
                0
                да это мелочи, ошибка никак не связанная с нхибернейт. +)
                сравнение айдишников действительно даст необходимый результат!
              +2
              NHibernate при работе с классами создаёт proxy объекты, поэтому необходимо все свойства делать виртуальными!
              Я несколько раз по началу попадал на эти грабли:)
                0
                угу, я такими их и сделал, правда забыл указать :-[
                0
                Вот если бы еще кто подсказал как здесь нормально оформить код. Сделал все по инструкции, а код не подсвечивает. %)
                  0
                  Всё просто: идёте сюда (http://source.virtser.net/default.aspx), вставляете свой код, на выходе получаете подсвеченный код нужного языка.
                    0
                    хм. да вы так и сделали:) Может быть теги ещё нельзя использовать вам?
                      0
                      Попробуйте отредактировать топик, у вас сейчас достаточно кармы, всё должно работать.
                      +2
                      NHibernate — отличная ORM и вообще инструментарий для DAL-уровня (Data Access Layer). Однако, мы предпочитаем использовать ADO.NET Entity Framework для подобных дел. А для некоторых проектов — SubSonic. В принципе, все инструменты — отличные. Даже удивительно, но не видел откровенно плохих ORM для .NET — даже у LINQ to SQL вся проблема только в том, что он только для SQL Server, но очень просто и удобен в использовании.
                        0
                        одновременно блин)
                          0
                          Есть же Linq провайдеры для MySql, Oracle и PostgreSQL, например здесь (http://code2code.net/Db_Linq/).
                            0
                            Ну эт то я в курсе. Я говорил конкретно про реализацию LINQ to SQL, т.е. отдельно очень проработанный для SQL Server. Просто это, в отличие от других, нативная технология.
                            А так, мы используем или использовали в свое время и LINQ to Active Directory, и LINQ to NHibernate, LINQ to MySQL и даже писали свои провайдеры, реализующие интерфейс IQueriable, позволяющий обращаться к объектам-экземплярам с помощью LINQ.
                            0
                            Я использовал DataObjects.Net на продакшене, всё рулило :)
                              0
                              я тоже сталкивался с этой библиотекой. единственный ее самый ощутимый минус — это убогая документация. я не про очевидные вещи конечно. да и на форуме их задаешь вопрос и потом месяц ждешь ответа. все-таки комьюнити у гибернейта побольше будет и своевременно можно получить ответ ;)
                                0
                                Фиг знает, мне всегда отвечали во время… А вот in-depth документация у них реально страдает, впрочем как и у всех, кого я смотрел.
                                  0
                                  Ну про SubSonic, LINQ to SQL и NHibernate я бы так не сказал — достаточно уроков, скринкастов и записей в блогах о том, как всем этим добром пользоваться.
                            +3
                            полезно,
                            хотя сейчас, после выхода vs sp1 и net 3.5 sp1 имхо интереснее сконцентрироваться на изучении нативных технологий, в смысле Entity Framework
                              0
                              Ага, благо нативные технологии там очень высокого уровня. Впрочем, ненативные NHibernate и SubSonic — тоже образец того, как надо писать библиотеки. Очень качественные продукты.
                              +1
                              не забудьте про nhibernate.attributes упомянуть. мне например удобно, когда все в одном месте. главное — не забывать order выставлять для них :)
                                +1
                                CodeSmith сам не содержит никаких шаблонов, а является только инструментом для кодогенерации. А вот к нему много разных шаблонов, по которым можно генерить и DAL, и целые фреймворки (например, nettiers.com/ — .netTiers Application Framework).
                                  +1
                                  Добавлю свою копеечку:
                                  При использовании ORM библиотек необходимо проводить тестирование производительности на ранних этапах разработки.
                                  Практически все ORM библиотеки грешат тем, что теряется контроль того, какие запросы они выполняют, а это может привести тормозам.

                                  На небольших проектах это не критично, но вот если проект большой, я предпочту, чтобы Data Access Layer был максимально прозрачным (это упростит последующую поддержку и ловлю багов).
                                  В последних нескольких проектах использую BlToolkit — очень нравится, но это не ORM.
                                    0
                                    NHibernate очень любит увлекаться кэшированием. В определенных задачах это конечно плюс, но иногда кроме диких тормозов это ничего не дает. Особенно при большом объеме данных и крупных выборках, которые регулярно встречаются при построении отчетов.
                                    Иногда приходится скрипя зубами отвергать удобный функционал NHibernate и грузить огромные коллекции в память и работать с ними уже там.
                                    Вобщем не забываем чистить кэш и оценивать количество запросов к базе которое ORM генерирует.
                                      0
                                      вообще, что касается отчетов, то мне кажется такие задачи все-таки не входят в круг решаемых ORM. Отчет это табличные данные а их удобнее обрабатывать на стороне сервера БД в хранимках например. А NHibernate умеет работать и с хранимками.
                                        0
                                        Абсолютно согласен. Это как пример того что ORM — не панацея, как может показаться новичкам, впервые освоившим его.
                                        Кроме того огромный плюс Hibernate — это возможность управлять структурой хранения данных и спокойно работать с ними напрямую. С ужасом вспоминаю Bold и ECO — то что они генерят, без поллитра не разобрать. И хранимок там уже не наваяешь.
                                          0
                                          Есть такое. Но все-таки большинство прикладных задач решаются именно с использованием ORM. Кстати, с LINQ to SQL и Entity Framework удобно работать с хранимками — они считают их по умолчанию методами модели приложения.
                                      0
                                      Мне интересно, есть ли отличия NHibernate от обычного Hibernate, который в Java?
                                        0
                                        Есть. NHibernate 1.2.1, о котором идет речь в статье, — это портированный джавовый Hibernate 2.1, Сейчас уже есть NHibernate 2 beta, который соответствует Hibernate 3.2. А последняя рабочая версия Hibernate — 3.3.0.0, т.е. сначала разрабатывается Java версия, и уже после этого все вкусности портируются под .NET.
                                        Во всем остальном — различия только в синтаксисе ;).
                                          0
                                          Вроде на днях зарелизился NHibernate 2
                                        0
                                        В чём премущество NHibernate перед LinqToSQL?
                                          0
                                          Если посмотреть несколькими постами выше, то можно увидеть один из недостатков LINQtoSQL, то что он дружит только с SQL Server. Да и вроде как это не совсем ORM. Из преимуществ NHibernate то, что он более зрелый и обкатанный.
                                          В «+» LINQ можно записать, то что он компилируется и то что он более «родной» для .Net'a.
                                            0
                                            разработчики NHibernate уже заявили о реализации LINQ провайдера для своего детища. Так что скоро запросы в NHibernate тоже можно будет конструировать с помощью LINQ и этот плюс уже не будет таким уж плюсом ;)
                                              +1
                                              Ну о том, как это сделать, уже достаточно давно написано, и это, кстати, одна из первых вещей, которую мы сделали, когда потребовалось использовать NHibernate в проекте.
                                            +1
                                            Сам по себе LinqToSQL является больше даже не ORM-библиотекой, а удобным способом работы с данными. Причем только с данными MS SQL Server. Сравнивать было бы корректнее Entity Framework с NHibernate.
                                            В LinqToSQL можно связать одну таблицу с одним классом в нашей модели. Этого достаточно в более простых приложениях, но при сложных структурах данных в это можно упереться.
                                            LinqToSQL не поддерживает связи в базе данных Many to Many. Нужно самому это как-то реализовывать.
                                            Классы, генерируемые LinqToSQL в основном выступают просто хранилищем, структурами. Внедрить в них бизнес-логику по обработке данных и взаимодействию друг с другом достаточно проблемно.

                                            Это как основные недостатки (если это можно назвать недостатками, просто концепции разные) LinqToSQL в сравнении с другими библиотеками. По отличиям может рассказать автор топика, что может делать NHibernate по сравнению с linq.
                                              0
                                              >В LinqToSQL можно связать одну таблицу с одним классом в нашей модели. Этого достаточно в более простых приложениях, но при сложных структурах данных в это можно упереться.
                                              Да, тут согласен полностью. «Упереться» — немного не то слово, но неудобно: начинаются врапперы и т.д… Хотя, ИМХО, что писать враппер, что сидеть XML строчить… Первое, я бы сказал, гораздо лучше.

                                              >Классы, генерируемые LinqToSQL в основном выступают просто хранилищем, структурами. Внедрить в них бизнес-логику по обработке данных и взаимодействию друг с другом достаточно проблемно.
                                              Аналогично написанному выше.

                                              >LinqToSQL не поддерживает связи в базе данных Many to Many. Нужно самому это как-то реализовывать.
                                              Он реализовывает это так же, как это реализовано в БД — через промежуточный класс/таблицу.

                                              В общем, ИМХО, что в лоб, что по лбу…
                                                +1
                                                Ну почему же. Логика по валидации вполне себе встраивается и нормально живет, используя возможности partial-классов. То же самое, кстати, касается и Entities в ADO.NET Entity Framework.

                                                А в целом LINQ to SQL еще развиваться и развиваться. Согласен, это не совсем ORM. Еще не слишком просто юнит-тестировать контекст данных LINQ (DataContext). Приходится создавать «test-specific fake data-context».

                                                Насчет Many-2-Many согласен с предыдущим комментатором вашего комментария — как и в БД, это реализуется через дополнительную таблицу, которая, соответвенно, в свою очередь переходит и в класс LINQ2SQL.
                                                  +1
                                                  Не знаю насколько будет дальше развиваться LinqToSQL как ORM система. EF не зря ведь писали :)

                                                  Связь ManyToMany, понятное дело, можно реализовать, но работа с ней уже не такой прозрачной будет, как с OneToMany, например. В этом как раз и недостаток я вижу. Мы не можем работать со связанными объектами как со «взрослыми» объектами, которые сами понимают что к чему. А так нужно ещё, с точки зрения логики, применять совсем лишнюю третью таблицу, которая с одной стороны как сущность, с другой стороны совершенно лишняя.

                                                  Хотя, если поизвращаться, то и к LinqToSQL тоже можно прикрутить связь ManyToMany.
                                                    +1
                                                    Ну с этим согласен, конечно! Концептуально, связь многие-ко-многим не должна быть сущностью. Это объект, описывающий отношение сущностей, в то время как в реляционной среде — это такая же «таблица», как и другие.

                                                    Поэтому, как раз, думаю, заморачиваться и извращаться не нужно, и там, где это оправдано — использовать Entity Framework, что мы, собственно успешно и делаем :) Действительно, не зря его разрабатывают.

                                                    Насчет сомнения по поводу LINQ to SQL, кстати — есть мнение, что это что-то вроде временного решения до появления EF, хотя и разрабатываются разными командами.
                                                0
                                                для меня основное преимущество — возможность работать на 1.1, 2.0 платформах
                                                  0
                                                  NHibernate нужно сравнивать скорее не с LINQ to SQL, а с другой разработкой от MS — ADO.NET Entity Framework.
                                                  0
                                                  расскажите потом как-нить, пожалуйста, с какими проблемами и недостатками ORM столкнулись в разработке
                                                  0
                                                  На данный момент, весь мой опыт работы с данными складывается из использования разнообразных ORM и лучшим решением (это, замечу, мое субъективное мнение) является на данный момент XPO от DeveloperExpress, следом за ним следует NHibernate затем SubSonik и LinqToSql. Одной из причин, по которой LinqToSql не может обойти конкурентов, является то, что он не умеет обновлять структуру базы данных, если в класс вносятся какие-либо изменения, приходится сносить базу и запускать создание по новой схеме. Вопрос решается сторонними примочками, но… это уже как-то некрасиво, на мой взгляд — это одно из первых умений, коим должен обладать ORM. Так что, XPO пока рулит. В плане же удобства использования ORM в сложных структурах — так мы их только потому и используем, что управлять объектами гораздо проще, чем копаться в SQL или чистом ADO.
                                                    0
                                                    NHibernate тоже не умеет обновлять базу, но это и логично, с учетом того сколько различных СУБД он поддерживает.

                                                    Для Firebird/Interbase я делаю проще. Обновление состоит из 3-х этапов:
                                                    1. Генерится новая временная база.
                                                    2. При помощи библиотеки из IBExpert метаданные сравниваются с метаданными основной базы и генерируется скрипт обновления.
                                                    3. Скрипт запускается на основной базе.

                                                    Естественно не все изменения можно применить, особенно если сильно меняется ссылочная структура, так что менять надо очень вдумчиво и внимательно, хотя это не излишне на всех этапах.
                                                    +1
                                                    а еще есть CastleProject ActiveRecord — надстройка над NHibernate, которая полностью избавляет от XML и позволяет все модели описать в коде с помощью аннотаций C#, унаследовав модели от ActiveRecordBase. Там же обеспечивается сохранение сущностей и загрузка их. При этом ActiveRecord не скрывает от пользователя сам NHibernate, давая доступ к сессиям и прочим хитростям NHibernate. Выполнена в полном соответсвии с ActiveRecord паттерном. Сам использовал в одном проекте и вполне доволен.
                                                      +1
                                                      От написания XML также избавляет NHibernate.Mapping.Attributes — стандартное дополнение к NHibernate.

                                                      Пример использования аттрибутов:
                                                      namespace BuisinessLayer.Directories
                                                      {
                                                        [Serializable]
                                                        [JoinedSubclass(NameType = typeof(Country), Table = «Countries», ExtendsType = typeof(PersistentObject), Lazy = true)]
                                                        public class Country: BuisinessLayer.PersistentObject
                                                        {
                                                          [Key(Column = «Id»)]
                                                          private string _nameRus;
                                                          private string _ISOCode;

                                                          [Property(Name = «NameRus», Length = 80)]
                                                          public virtual string NameRus
                                                          {
                                                            get { return _nameRus; }
                                                            set { _nameRus = value; }
                                                          }

                                                          [Property(Name = «ISOCode», Length = 3)]
                                                          public virtual string ISOCode
                                                          {
                                                            get { return _ISOCode; }
                                                            set { _ISOCode = value; }
                                                          }
                                                        }
                                                      }
                                                      * This source code was highlighted with Source Code Highlighter.


                                                      А за наводку на ActiveRecords — спасибо, покопаем.
                                                        0
                                                        По поводу супер-грамотно реализованного паттерна ActiveRecord в ORM — очень рекомендую посмотреть SubSonic.
                                                        0
                                                        на тему сравнения различных ORM для .Net можно еще почитать здесь: yuryskaletskiy.blogspot.com/2008/07/net-orm.html
                                                          0
                                                          Тыкал я его, серавно гавно по сравнению с простотой db40

                                                          Те же маппинг-файлы…

                                                          Гемор короче.

                                                          Опять же в любом ORM`е пример для даунов прекрасно работает, а вот как там сделать вложенные коллекции, да так, чтобы по разному грузились? В java`вском hibernate пробовал читать, но недопонял — наверное позже придется все-таки его ковырять.

                                                          А так моя ближайшая мечта — db40 или что-то подобное, тока когда оно станет похоже на правду, чтобы можно было под нагрузкой посмотреть.
                                                            0
                                                            ну зачем же гадости сразу? я же не кричу что NHibernate — это круто, а все остальное г***. Идеальных технологий и решений не бывает. да и если лопату брать не стого конца, думаю, копать будет очень трудно.
                                                              0
                                                              Я про ORM`ы в-принципе.

                                                              2trix: Вот это вот и прискорбно, что мы вынуждены сидеть на sql`е, коего плюс только в том, что он не дерево, а таблица.

                                                              А я человек и хочу мыслить как буратино — деревьями и графами*!

                                                              ____________________________________________
                                                              * Как деревья хранить в SQL в курсе, здесь я о другом
                                                              0
                                                              пока не видно предпосылок к тому, чтобы объектные базы были сравнимы по эффективности с реляционными. так что db4o — удел приложений с небольшой встроенной базой.
                                                              а если помнить о портабельности и удобстве администрирования, то окажется что для встроенной базы лучше использовать что-то типа hsql

                                                              0
                                                              Как я понимаю — для CRUD будет генерироваться SQL запрос. А кодогенерация при активной нагрузке будет активно вымывать КЕШ БД. За что в больших корпоративных системах могут просто расстрелять
                                                                +3
                                                                я пока не считаю себя гуру NHibernate, но насколько я знаю, генерация будет только при первом обращении, а потом все будет хранится в кэше, так что проблем с этим быть не должно.
                                                                  0
                                                                  Хм. Похоже не совсем корректно высказался.
                                                                  Рассмотрим пример запроса через NHibernate, например, на чтение одной записи по ID.
                                                                  Select [… fields...] from TABLE WHERE id='некоторое число'

                                                                  Соответственно данное значение будет подставляться при кодогенерации и мы получим
                                                                  Select [… fields...] from TABLE WHERE id='1'

                                                                  Select [… fields...] from TABLE WHERE id='5'

                                                                  Select [… fields...] from TABLE WHERE id='15'

                                                                  Именно генерация sql строк и приведет к вымыванию из кеша БД закешированных запросов.
                                                                    0
                                                                    Нет, вы неправы. Запрос будет следующим Select [… fields...] from TABLE WHERE id= @Id. то есть как раз то запрос закэшируется и в него просто буду подставляться параметры. неужели вы думаете там идиоты сидят? ;)
                                                                    • UFO just landed and posted this here
                                                                  +1
                                                                  >>В проекте предполагалось использование БД — исправьте
                                                                    0
                                                                    спасибо, поправил ;)
                                                                    0
                                                                    Я вот тоже решил осовить для себя orm, и ваши статьи мне очень помогают в расширении кругозора. Опять же встал вопрос выбора. EF ждать еще долго, и из существующих NHibirnate выглядит очень привлекательно. Не подскажите только где можно почитать (или может сами поделитесь?) про отличия (преимущества/недостатки) в сравнении с strongly typed datasets.
                                                                      0
                                                                      А где следующие части?

                                                                      Only users with full accounts can post comments. Log in, please.