NHibernate vs. Entity Framework 4.0

Original author: Oren Eini
  • Translation
Это вопрос мне задают очень часто, и я всегда старался уклониться от прямого ответа, но все же меня так часто об этом спрашивают, что я чувствую, что я просто обязан ответить. В общем-то я больше склоняюсь к NHibernate, поэтому, когда вы читаете эту статью, пожалуйста, имейте это в виду.

В EF 4.0 исправлено очень много проблем, существующих в предыдущей версии EF. Такие вещи как прозрачная «lazy loading», POCO классы, code only и т.д. EF 4.0 явно гораздо приятнее чем EF 1.0.

Проблема в том, что EF все еще очень молодой продукт. Все изменения, которые были добавлены в 4 версию лишь коснулись поверхности. Я уже писал о некоторых из моих проблем с моделью POCO в EF и Code Only, поэтому я не буду повторяться. Судя по описанным мной проблемам, основная сложность в том, что между опытом сообщества и тем, что делает Microsoft есть стена. Оба этих случая показывают типичные проблемы, с которыми мы столкнулись в NHibernate и Fluent NHibernate. Эти вопросы были рассмотрены и решены в NHibernate, но появляются в EF.

Тем не менее, даже игнорируя рассмотренные мной проблемы, есть и другие признаки того, что NHibernate зрелый продукт. Я понимал это, когда я писал руководство по Entity Framework Profiler’у; есть вещи, которые вы просто не можете сделать с помощью EF, но которые являются естественной частью NHibernate.
Я не буду пытаться создать список различий по пунктам. Мы рассмотрим те случаи, где есть существенные различия между возможностями NHibernate и EF 4,0. В основном это различия в возможости тонкой настройки того, что делает фреймворк. Как правило, это настройки, позволяющие достигнуть большей производительности системы без ущерба использования OR/M.

Итак, вот небольшой список:
  • Пакетная запись — NHibernate может быть сконфигурирован для пакетной записи в базу данных; в случае когда вам нужно выполнить несколько команд записи в БД, NHibernate может сделать это за одно обращение к БД, вместо того чтобы обращаться к БД для каждой команды.
  • Пакетное чтение/множественные запросы/Future функции — NHibernate может сделать это за одно обращение к БД, вместо того чтобы обращаться к БД для каждой команды.
  • Пакетная загрузка коллекций — когда вы загружаете коллекцию с помощью «lazy loading», NHibernate может найти и другие коллекции того же типа, которые не были загружены, и загрузить все за одно обращение к БД. Это отличный способ избежать необходимости SELECT N+1.
  • Коллекции с «lazy loading» («экстра») — Extra Lazy означает, что NHibernate адаптируется к операциям, которые можно запустить на верхней части коллекции. Это означает, что blog.Posts.Count не заставит загрузить всю коллекцию, а скорее создаст выражение «select count(*) from Posts where BlogId = 1», и что для вычисления blog.Posts.Contains() будет также выполнен запрос, а не будет произведена загрузку всей коллекции в память.
  • Фильтры коллекций и страничные коллекции — это позволяет определить дополнительные фильтры (в том числе разбивку на страницы!) на верхней части вашей коллекции, а это означает, что вы можете легко перемещаться постранично по blog.Posts, и вам не придется загружать всю коллекцию в память.
  • Кэш 2-го уровня — управление кэш-памяти является сложной задачей, я уже указывал, почему это важно, так что пропущу это на этот раз.
  • Тонкая настройка — это то, что имеет решающее значение, когда вам нужно что-то чуть-чуть сверх того, что обеспечивает фреймворк. С NHibernate, почти во всех случаях, вы можете улучшить существующий фреймворк, с EF — вы полностью и окончательно заблокированы.
  • Интеграция и расширяемость — у NHibernate есть большое число дополнительных проектов, таких как NHibernate Search, NHibernate Validator, NHibernate Shards и т.д. Для EF таких проектов не только не существует, но они и не могут быть написаны, потому что для EF просто не предусмотрена такая возможность.
Однако, с другой стороны:
  • для EF 4.0 существующий Linq провайдер реализован лучше, чем в текущей версии NHibernate. Это то, над чем активно работали в NH 3.0, чтоб исправить этот пробел.
  • EF от Microsoft.

От переводчика: сам в данный момент участвую в небольшом проекте ASP.NET MVC2 + Entity Framework 1.0. С другими OR/M не работал, поэтому стало интересно сравнение NHibernate vs. Entity Framework. Интересно мнение тех, кто плотно работал с обоими OR/M (или другими) — все ли верно написал мистер Oren Eini? есть ли вам что добавить, поправить?
Share post

Similar posts

Comments 16

    +2
    EnEntity Framework 4.0 поддерживает Microsoft Access
      0
      Вообще это был вопрос, но раз не знаете так не знаете :)
      0
      >> ASP.NET MVC2 + Entity Framework 1.0
      Ох намучаетесь :( Как по мне так лучше Linq2Sql чем, EF 1.0. В L2S все баги можно бесболезнено отворкэраундить, в EF 1.0 — это сложно.
        0
        Мучаемся, но двигаемся вперед :) Думаю о переходе на EF 4.0, правда не знаю на сколько болезненно/безболезненно он пройдет…
          0
          Если есть, возможность\время перейти, то вперед. Как говорят, пора перестать откапывать стюардессу (EF 1.0) :)
          Всяко легче будет, чем переход на NHibernate, если вы ищете альтернатив.
            0
            Довольно безболезненно пройдет — пробуйте и не пожалеете. По сравнению с EF1 там только плюсы. Ни за что не рекомендовал бы Linq2Sql — незачем использовать в production-проекте (с перспективой поддержки) технологию, брошенную самим производителем.

            Если хочется альтернатив — конечно же, NHibernate, а также обязательно посмотрите LightSpeed и (внимание, ActiveRecord!) — SubSonic.
              +1
              Реализовали проект ASP.NET + EF 1.0. В процессе реализации постоянно возникали какие-то вопросы и невозможность реализации определенных требований архитектуры. Все-таки недоработанный фреймворк был.

              Лучше сразу переходите на EF 4.0, либо NH.
            0
            Работал и с NHibernate, и с EF 1.0. Субъективно NHibernate понравился чуть больше. Но LINQ для запросов удобнее и приятнее, чем HQL.
              +1
              В блоге у Орена справедливо подметили просто неадекватный метод запросов:
              ICriteria criteria = Session.CreateCriteria(typeof 
              (Person), "pers") 
              .Add(Expression.Eq("pers.Customerid", 1));; 
              DetachedCriteria subCriteria = 
              DetachedCriteria.For("persAddr"); 
              subCriteria.Add(Expression.Conjunction() 
              .Add(Expression.Like("persAddr.State", "MA")) 
              .Add(Expression.EqProperty 
              ("persAddr.PersonID","pers.PersonID"))); 
              subCriteria.SetProjection(Projections.Id()); 
              criteria.SetResultTransformer(new 
              NHibernate.Transform.DistinctRootEntityResultTransformer()); 
              retObject = criteria.List() as List; 
              

              Считаю, что нужно запретить все query API кроме LINQ. А с LINQ у NHibernate как раз проблемы. Сам использую OpenAccess.
                0
                Как он вам, кстати? В крупных проектах используете? Баги? Производительность?
                  0
                  Мне определенно нравится. Все просто и удобно. Использую для взаимодействий с крупными базами (например itbonus, закупки, итд), аналитика через linqpad и excel работает достаточно быстро. Правда по сложности там ничего особенного нет. Баги — почти не встречал, есть конечно проблемы с SQL Server CE, но это скорее вина авторов SQL Server'а нежели Telerik. Вообще техсаппорт у Телерика отменный — очень быстро реагируют на сообщения, помогают разруливать проблемы.
                +1
                Как показала практика для bulk(пакетных) inserto-в лучше всего использовать нативные методы, тут ORM себя плохо проявляет, в частности и NHibernate. Ну и отсутствие query over language у NHibernate удручает.
                  0
                  А я использую LinqToSql в большинстве своих проектов, и очень доволен его работой, а главное, предсказуемостью результата. Работал с EF, намучился ввиду большого числа ограничений и не оптимизированного SQL — поэтому отказался от его использования. NHibernate тоже пробовал. Отказался из-за слабой поддержки Linq-синтаксиса.
                    +7
                    И в NH и в EF, есть чисто идеологические проблемы. Ясен байт Орен нахваливает NH и заводит свою любимую песню о том, что MS не учитывает опыт накопленый сообществом (он ноет по этому поводу уже года два), подразумевая «почему они не взяли мой NH». Но зачем нужен второй NH? Один уже есть. С другой стороны EF тоже не идеал, они таки делают еще один ORM, точно такой же, но другой.
                    Мне очень нравилось как это начиналось, но… Впрочем история построения ORM в MS весьма богата, напомню в краце основные вехи:

                    Давным давно, еще до выхода FW 1.1 на конференции PDC 2003, традиционно проходящей в Лос-Анжелесе, MS официально объявил о начале работ над технологией взаимодействия с данными под официальным названием «ObjecSpaces». Суть в том, что команда OS нашла фатальный недостаток в существующих ORM (их придумали не они), и решила этот недостаток устранить. Ну, поскольку дело хорошее, то с песнями и плясками приступили, и на вышеупомянутом PDC был предложен даже некий прототип… Но что-то пошло не так, что именно сейчас уже дело темное, и спустя какое-то время проект был заморожен. Тем временем, активно шли работы над другим забавным проектом, под названием WinFS — грубо говоря, это должна была быть объектная файловая система, причем данные должны были лежать в SQLServer-е. Очевидно при таком сценарии без ORM никуда вот и команда ObjectSpaces быстро нашла фатальный недостаток в их системе мапинга (ее придумали не они) и дружно влилась в стройные ряды WinFS team (причем предполагалось, что ObjecSpaces будет поставляться вместе с WinFS в качестве библиотеки). Но, что-то пошло не так, сейчас уже дело темное, и проект WinFS оказался заморожен. Тем временем, в светлую голову Эрика Мейера, пришла идея LINQ и он сумел вложить ее в головы Коробкина, Хайлсберга и других талантливых ребят из MS, и они начали ее продвигать и разрабатывать. Ясен байт, что подсистема LINQ-а, отвечающая за работу с RDBMS практически ORM (тогда она называлась DLINQ) и команда OS не смогла устоять перед искушением, нашла, по привычной схеме, фатальный недостаток и занялась рализацией DLINQ. В этот момент я, признаюсь, стал тревожится за успех этого во всех отношениях достойного мероприятия.
                    Далее случился гениальный ход, DLINQ трансформировался в LINQ2SQL, и образовался еще один проект — EF (тяжелый ORM для «серьезных» задач), куда и перешла команда ObjectSpase. После этого LINQ2SQL зарелизился практически в срок, а выход EF отложили на год-полтора…
                    Я уже было вздохнул спокойно, но тут произошла досадная фигня — LINQ2SQL остался без хозяина, его разрабатывала часть команды компилятора шарпа и дальше его поддерживать им было не с руки. Какое то время этот проект помыкался бесхозным, его пытались всучить команде MS SQL и в итоге его приписали к команде EF, где и сгнобили по тихому, пообещав реализовать его функционал в рамках EF.
                    А между делом, таки да, свершилось чудо и EF вышел. Правда первая версия была совсем сырая и к продакшену не пригодная, но ее просто нужно было выпускать. Сейчас вроде по лучше, но идеология там все-таки не для легковесных ORM, да и косяков по прежнему много.

                    Из того, чем можно пользоваться сейчас:
                    1. NH — меня он не устраивает по идеологическим причинам и в силу своей тяжеловестности. Да, я знаю, я все знаю. Орен действительно прав, за долгие годы существования этого продукта, его таки вылизали до невозможного состояния и действительно смогли сделать достаточно гибким, чтобы им можно было пользоваться практически как угодно. Но за это же время он оброс кучей всякого хлама и использовать его правильно сильно сложнее, чем неправильно. Начинающему разработчику, в серьезном проекте, без присмотра старших — строго не рекомендуется.

                    2. EF — все еще сырой, идеологические косяки те же что и в NH, да еще и не достаточно гибкий, так как изначальная архитектура еще ObjectSpase в нем до сих пор ощущается. Задумка в самом начале была не плоха, при условии ориентации этого продукта на достаточно узкий класс задач, но когда из него попытались сделать универсальный инструмент, получилась какая-то фигня.

                    3. Linq2SQL — так как делалася талантливыми дядьками, четко представляющими, что они хотят получить в конечном итоге, и не замахивающимися на универсальные всемогутеры, то получился отличный инструмент, с правильной идеологией. Вообще, удивительный факт — первый и единственный релиз оказался на столько удачным, что им можно пользоваться в продакшене до сих пор. Что я с удовольствием и делаю в нескольких проектах. Очень жаль, что MS не стал развивать его как отдельный продукт.

                    4. На мой взгляд, лучшим на данный момент ORM подобным инструментом является BLToolKit (http://bltoolkit.net). Это то, каким должен был бы быть LINQ2SQL, если бы MS его не забросил. Отличительные особенности:
                    — правильная идеология (ORM не делает ничего лишнего и не пытается защитить хрупкий мозг разработчика от БД, а просто избавляет его от рутинной работы)
                    — отличная поддержка LINQ
                    — поддержка около 20 различных СУБД
                    — это самый быстрый ORM на данный момент (того же NH на некоторых задачах рвет в десятки раз)
                    — в ближайшее время должен появиться (если еще не.) LINQ DML. Вот это вообще мегафича.
                      0
                      Не смотрели в сторону DataObjects.net?
                      0
                      А как уважаемые хабровчане относятся к шаблонам .netTiers?

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