.net ORM-сравнение

Я разговаривал с кем-то о платформе Entity Framework, и я пока не в нее вникаю, но я хотел бы изучить ее. Тем не менее, я все еще смущен, должен ли я это изучать или нет. Я слышал много людей, говорящих, что вы не должны использовать фреймворк сущности, но я не слышал никаких аргументов, почему это так.

Итак, мой вопрос: какие pro и con используют Entity Framework по сравнению с другими продуктами. Как

  • NHibernate
  • DataObjects.Net
  • и т.д..

С точки зрения простоты использования, тестируемости, семантики...

Я знаю, что есть несколько дубликатов questions об этом. Но все они устарели (2008,2009), и, честно говоря, в аргументах также нет чего-то. Я знаю, что Entity Framework 4.0 доступен, и я пока не нашел хорошего (полного) сравнения.


Ответы

Некоторые из приятных людей здесь ответили на мой вопрос, объяснив некоторые подробности о разных рамках. Думал, что было бы неплохо показать их здесь для дальнейшего использования.

Ответ 1

Поскольку Дж. Тихон отлично справился с объяснением функций EF, я просто перечислил области, в которых NHibernate запускает круги вокруг EF:

  • Кэширование
    • EF не имеет ничего из коробки; там просто неподдерживаемый образец
    • NH имеет полную поддержку кэширования, включая недействительность на основе БД. Он также расширяемый и основанный на провайдерах, что означает, что он работает с различными типами локальных и распределенных кэшей.
  • Дозирование
    • EF не имеет
    • NH имеет обширную поддержку групп ленивой загрузки объектов или коллекций сразу (в любом БД) и сохраняющихся изменений одинаково (Oracle и SQL Server). Там также многопользовательские и будущие запросы, позволяющие произвольно группировать разные запросы, отправляемые в одном обратном направлении.
  • Типы пользователей
    • EF не имеет расширяемости. Он даже не поддерживает свойства Enum.
    • В NH не привязаны никакие сопоставления типов. Вы можете расширить его для поддержки любых типов значений, которые вы можете создать, изменить способ отображения существующих типов и т.д.
  • Поддержка коллекции
    • EF поддерживает только простые коллекции объектов. Многие-ко-многим всегда используют составной ключ
    • NH поддерживает коллекции объектов, типы значений, типы компонентов, а также индексированные коллекции и словари (где и ключ, и значение могут быть любого типа). Поддерживаются коллекции "многие ко многим" с собственным ключом (idbag).
  • Logging
    • EF не имеет выхода из строя. Там же неподдерживаемый образец, указанный выше
    • NH имеет обширную регистрацию, что позволяет легко отлаживать проблемы. Он использует log4net по умолчанию, но вы можете использовать любую структуру ведения журнала, которую вы хотите.
  • Запросы
    • EF имеет LINQ в качестве основного языка запросов. LINQ имеет высокий импеданс при сопоставлении с реляционными базами данных. Поставщик EF не поддерживает использование объектов в качестве параметров; вы всегда должны использовать идентификаторы. Там также язык запросов, который плохо документирован
    • NH имеет LINQ (не так полно, как EF, хотя), HQL, QueryOver и Criteria.
  • Система событий и перехватчики
    • EF почти ничего не имеет.
    • NH имеет мощную систему событий, которая позволяет продлить или заменить ее поведение в любой момент сеанса lifecyle: загрузка объектов, сохраняющиеся изменения, сброс и т.д.

Я думаю, что расширяемость - главная точка продажи. Каждый аспект NH корректно отделен от остальных, используя интерфейсы и базовые кланы, которые вы можете расширять, когда вам нужно, и отображаться в настройках.

EF следует обычному шаблону MS, делающему вещи закрытыми по умолчанию, и мы увидим, что расширилось позже.

Ответ 2

Я трачу огромное количество времени на изгиб Entity Framework на свои нужды и поэтому могу сказать, что он выполняет большинство требований, которые вы хотите от ORM. Но некоторые аспекты слишком сложны, поскольку другие ORM показали, что это можно сделать проще.

Например, начать работу с Entity Framework довольно просто, так как вы можете просто запустить Designer в Visual Studio и работать с ORM за считанные минуты. Но в итоге вы получаете Entity-Classes, привязанные к ObjectContext, созданным дизайнером (этого можно избежать с помощью настраиваемого шаблона T4). Это не обязательно плохо, но это похоже на Microsoft "Начало работы", которое вы не хотите использовать в реальном приложении.

Но если вы погрузитесь глубже в Entity Framework, вы увидите, как вы можете избежать большинства ошибок: Дизайнер создает файл EDMX, который (если вы посмотрите на него в редакторе XML) - это не что иное, как комбинация из трех основных аспектов ORM, физического хранилища (вашей базы данных), концептуальной модели (классы сущности) и сопоставления между ними. Пользовательское действие сборки, применяемое к файлам .edmx в Visual Studio, разделит эти 3 части на три отдельных файла и добавит их в сборку в виде встроенных ресурсов. При создании ObjectContext путь к этим трем файлам используется в ConnectionString (который всегда выглядит немного запутанным для меня). То, что вы на самом деле можете сделать здесь, - все это делается самостоятельно. Это означает запись схемы хранения, концептуальной модели и отображения в XML-редакторе (так же, как и NHibernate), и встраивания их в сборку, содержащую вашу модель.

Базовый базовый класс Entity Framework "ObjectContext" может быть построен из этих трех файлов (требуется MetadataWorkspace и EntityConnection), но дело в том, что вы полностью контролируете создание объекта ObjectContext. Это открывает двери для многих функций, которых вы не ожидаете от Entity Framework. Например: вы можете встроить несколько схем хранения SSDL в одну сборку для соответствия определенному типу базы данных (обычно я добавляю один для SQL Server и один для SQL Server CE 4.0). И создайте перегрузку конструктора, которая выбирает подходящую схему хранения для определенного типа DbConnection.

Поскольку у вас есть собственная реализация ObjectContext, вы можете реализовать на ней различные интерфейсы. Как и ваш собственный IRepository, но поскольку мне нравится подход ObjectContext, я создаю что-то вроде:

interface ICatalog
{
    IEntitySet<Article> { get; }
    void Save();
}

interface IEntitySet<T> : IQueryable<T>
{
    void Add(T);
    void Remove(T); 
}

class EntityFrameworkCatalog : ICatalog
{
    ...
}

Но создание репозитория, если у вас есть объектная структура ObjectContext, очень проста, плюс вы получаете IQueryable. Исходя из этой информации, вы можете избежать сильной связи между вашими службами и ORM и полностью измотать структуру Entity Framework в тестах. Кроме того, при тестировании реализации Entity Framework вы можете использовать базу данных SQL Server CE во время модульных тестов, чтобы убедиться, что ваши сопоставления прекрасны (как правило, разные схемы хранения для CE и полномасштабного SQL Server - это всего лишь несколько данных, типов). Таким образом, вы можете проверить все варианты исполнения Entity Framework просто отлично.

Это заставляет Entity Framework хорошо сочетаться с современными концепциями программного обеспечения, но это не навязывает вам такую ​​практику, что упрощает "Начало работы".

Теперь к сложным битам: у Entity Framework есть небольшой набор поддерживаемых типов CLR, которые в основном включают только примитивные, такие как ints, строки и байтовые массивы. Он также обеспечивает некоторый уровень сложных типов, которые следуют тем же правилам. Но что, если у вас есть сложное свойство объекта, такое как представление документа DOM, которое вы хотели бы преобразовать в XML в базу данных. Насколько я знаю, NHibernate предоставляет функцию IUserType, которая позволяет вам определить такое сопоставление для вас. В Entity Framework это становится намного сложнее, но по-прежнему в нем все по-своему. Концептуальная модель позволяет включать в себя комплексные комплексные типы сборки (пока вы укажете ObjectContext об этом (ObjectContext.CreateProxyTypes(Type [])). Таким образом, вы можете создать оболочку для вашего исходного типа, которая известна только для Framework Entity Framework:

 class Document : IXmlSerializable { }
 class Article
 {
     public virtual Document Content { get; set; }
 }
 internal class EntityFrameworkDocument : Document
 {
     public string Xml
     {
         get
         {
              // Use XmlSerializer to generate the XML-string for this instance.
         }
         set
         {
              // Use XmlSerializer to read the XML-string for this instance.
         }
     }
 }

Вместо того, чтобы EF теперь может возвращать эти сериализованные документы из хранилища, записывая их на него, требуется перехватить хранение статьи и заменить простой документ на EntityFrameworkDocument, чтобы гарантировать, что EF может его сериализовать. Я уверен, что другие ORM делают это довольно легко, и это ухудшается. В настоящее время нет способа сделать то же самое с классом System.Uri(который является неизменным, но в противном случае работает) или Enum. Помимо этих ограничений вы можете вместить EF в большинство ваших потребностей. Но вы потратите много времени на это (как и я).

Поскольку мой опыт работы с другими ORM ограничен, я бы подвел итог:

  • Entity Framework находится в GAC, даже в профиле клиента
  • Entity Framework может быть настроена для представления даже сложных типов сущностей (включая некоторые саморегуляции "много-ко многим" или, например, сериализацию XML)
  • Он может быть "отвлечен", поэтому вы можете придерживаться IRepository и т.д.
  • Реализация IQueryable (хотя это не так полно, как DataObjects.Net)
  • Для этого требуется только System.Data и System.Data.Entity, вы можете даже включить несколько схем хранения для других поставщиков, которые обычно требуют ссылки, но если вы придерживаетесь DbConnection, вы можете просто сделать это:

    ICatalog Create(DbConnection connection, string storageSchemaPath) ICatalog CreateMySql(DbConnection mySqlConnection) { return Create(connection, "res://Assembly/Path.To.Embedded.MySql.Storage.ssdl"); }

Edit Недавно я узнал, что если ваши сущности и ваша реализация "каталога" находятся в одной и той же сборке, вы можете использовать внутренние свойства для процесса сериализации XML. Поэтому вместо выведения внутреннего EntityFrameworkDocument из Document вы можете добавить внутреннее свойство, называемое Xml, в класс Document. Это по-прежнему применяется только в том случае, если у вас есть полный контроль над вашими сущностями, но он устраняет необходимость перехвата любых изменений в каталоге, чтобы убедиться, что ваш производный класс используется. CSDL выглядит одинаково, EF просто позволяет отображаемому свойству быть внутренним. Я все же должен убедиться, что это будет работать в средах среднего доверия.

Ответ 4

Когда мы используем ADO.NET с нуля рано или поздно, мы расстраиваемся и начинаем искать другие решения. Я тестировал многие из них. Большинство из этих структур ORM имеют множество функций и требуют большого количества знаний. Некоторые из них кажутся очень легкими в начале (например: EF, Castle ActiveRecord), но есть много вещей, о которых вы должны заботиться:

  • Кэширование
  • Отношения "многие ко многим"
  • Lazy loading
  • Наследование
  • Композитные клавиши
  • Как инкапсулировать инфраструктуру из вызывающих абонентов
  • Как генерируются инструкции SQL
  • Производительность
  • Как сделать расширенные запросы к базе данных

Если вы опытный разработчик, и вы готовы ко всем этим ловушкам и материалам, я спрашиваю вас: также ваши товарищи по работе?

Есть более простые способы кодирования ADO.NET и не потерять контроль над тем, что происходит. Взгляните на PainlessDAL.

"Элегантное" кодирование не всегда является лучшим способом.