Хотелось бы в одном месте, например в одном топике собрать все проблемы которые вытекают из обьектно ориентированного способа работы с данными (БД) и использовании ORM средств.
Очень желательны примеры кода!
Хорошие статьи на эту тему тоже приветствуются.
Для разминки сразу вставлю свои 5 копеек — Практически все ORM заставляют пользователя использовать LazyLoad, без него они практически не работоспособны.
Здравствуйте, Tom, Вы писали:
Tom>Всем привет,
Tom>Хотелось бы в одном месте, например в одном топике собрать все проблемы которые вытекают из обьектно ориентированного способа работы с данными (БД) и использовании ORM средств. Tom>Очень желательны примеры кода!
Сильно зависит от ORM.
Tom>Для разминки сразу вставлю свои 5 копеек — Практически все ORM заставляют пользователя использовать LazyLoad, без него они практически не работоспособны.
Контрпример — Linq2SQL и EF вполне работоспособны без LL.
Tom>Ну и статья так же для разминки Tom>http://blogs.tedneward.com/2006/06/26/The+Vietnam+Of+Computer+Science.aspx
Без рассмотрения конкретных примеров — безсмысленно.
Сейчас недостатки Linq2SQL и EF заключаеются в отсуствии DML (insert\update\delete) и слабой поддержки возможностей SQL (особенно у EF).
Tom>>Для разминки сразу вставлю свои 5 копеек — Практически все ORM заставляют пользователя использовать LazyLoad, без него они практически не работоспособны. G>Контрпример — Linq2SQL и EF вполне работоспособны без LL.
Linq2SQL Я бы ORM-ом не считал вообще. EF я вообще затрудняюсь классифицировать. Но LazyLoad они прикручивают в V2 (или V4 как они сами её называют.)
G>Сейчас недостатки Linq2SQL и EF заключаеются в отсуствии DML (insert\update\delete) и слабой поддержки возможностей SQL (особенно у EF).
Я бы рассматривал более широкий набор ORM тулов. Например NHibernate
Здравствуйте, Tom, Вы писали:
Tom>Всем привет,
Tom>Хотелось бы в одном месте, например в одном топике собрать все проблемы которые вытекают из обьектно ориентированного способа работы с данными (БД) и использовании ORM средств. Tom>Очень желательны примеры кода!
Все эти проблемы вытекают из того, что почти все популярные ORM-движки навязывают разработчику концепцию построения объектной модели из реляционной модели, а не наоборот
Здравствуйте, Tom, Вы писали:
Tom>>>Для разминки сразу вставлю свои 5 копеек — Практически все ORM заставляют пользователя использовать LazyLoad, без него они практически не работоспособны. G>>Контрпример — Linq2SQL и EF вполне работоспособны без LL. Tom>Linq2SQL Я бы ORM-ом не считал вообще.
Тогда определение ORM в студию.
Tom>EF я вообще затрудняюсь классифицировать. Но LazyLoad они прикручивают в V2 (или V4 как они сами её называют.
В Linq2SQL lazy load с самого начала был, но это никак не отменяет того факта что они отлично и без LL работают.
Здравствуйте, baranovda, Вы писали:
B>Здравствуйте, Tom, Вы писали:
Tom>>Всем привет,
Tom>>Хотелось бы в одном месте, например в одном топике собрать все проблемы которые вытекают из обьектно ориентированного способа работы с данными (БД) и использовании ORM средств. Tom>>Очень желательны примеры кода!
B>Все эти проблемы вытекают из того, что почти все популярные ORM-движки навязывают разработчику концепцию построения объектной модели из реляционной модели, а не наоборот
Да ну?
Linq2SQL даже метод имеет — CreateDatabase, который угадай чего делает.
В EF в v4 добавили schema generation.
Здравствуйте, Tom, Вы писали:
Tom>Для разминки сразу вставлю свои 5 копеек — Практически все ORM заставляют пользователя использовать LazyLoad, без него они практически не работоспособны.
Скорее наоборот, практически все ОРМ умеют LL, но вполне работоспособны и без него.
Есть проблема массовых апдейтов и делитов, решена в NH 2.1alpha. Проблема partially load и типизации с compile-time контролем запросов решена в linq. Надеюсь к концу года увидеть рабочий linq2nhibernate, благо все необходимые изменения в NH для этого уже готовы. Контроль запросов при инициализации NH там уже возможен при условии хранения запросов в маппингах.
Осталась проблема двойной схемы, но она не так уж остра.
Z>Скорее наоборот, практически все ОРМ умеют LL, но вполне работоспособны и без него.
Без него можно работать практически всегда в теории, на практике перфоманс проседает так что работать невозможно.
Z>Есть проблема массовых апдейтов и делитов, решена в NH 2.1alpha. Проблема partially load и типизации с compile-time контролем запросов решена в linq. Надеюсь к концу года увидеть рабочий linq2nhibernate, благо все необходимые изменения в NH для этого уже готовы. Контроль запросов при инициализации NH там уже возможен при условии хранения запросов в маппингах.
Z>Осталась проблема двойной схемы, но она не так уж остра.
А можно про неё по подробнее? Я не в теме просто.
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, baranovda, Вы писали:
G>Да ну? G>Linq2SQL даже метод имеет — CreateDatabase, который угадай чего делает.
И чё? Это стало быть она из экземпляра DataClasses сможет мне все функции, хранимки, триггеры и вьюхи в пустой базе построить? индексы повесить?
Здравствуйте, Ziaw, Вы писали:
Z>Здравствуйте, Tom, Вы писали:
Tom>>А можно про неё по подробнее? Я не в теме просто.
Z>Так она описана в твоем линке, схема данных и маппинг дублируют много информации, хотя часто можно сделать автосинхронизацию.
FluentHNibernate, его AutoMapping фитчер. У нас все мапинги сторяться в рантайме и соотвевенно дублирования нет. Есть небольшие исключения, но они решаються кастомными конвеншенами.
Здравствуйте, Tom, Вы писали:
Tom>Для разминки сразу вставлю свои 5 копеек — Практически все ORM заставляют пользователя использовать LazyLoad, без него они практически не работоспособны.
Чепуха, у нас NHibernate и при этом все eager loading. А с чего вы вообще сделали такой вывод? Какими ОРМ вы пользовались?
Здравствуйте, Mike Chaliy, Вы писали:
MC>FluentHNibernate, его AutoMapping фитчер. У нас все мапинги сторяться в рантайме и соотвевенно дублирования нет. Есть небольшие исключения, но они решаються кастомными конвеншенами.
Читаем внимательно, дублируются маппинги и схема данных. Маппинги у вас строятся автоматически по классам, а не по схеме данных.
Здравствуйте, Tom, Вы писали:
Tom>Хотелось бы в одном месте, например в одном топике собрать все проблемы которые вытекают из обьектно ориентированного способа работы с данными (БД) и использовании ORM средств.
Несколько неверная постановка вопроса. ORM — это все таки некоторая абстракция которая обладает способностью делать из рекордсета того или иного вида объекты. А вот дальше начинаются фичи, которые обладают теми или иными достоинствами и недостатками. И они сильно зависят от того, или иного продукта. Так что тут полноценный риск менеджмент.
Ну например:
Сама схема. Есть ли синхронизация между схемой БД и объектной моделью. Какие действия если они рассинхронизированы. Если есть репортинг, в которых мы вынуждены относиться к данным как к данным, что мы будем делать?
Построитель SQL. Есть ли у нас большие данные? Можем ли мы выполнять чистый SQL?
Наличие кэша. Будет ли кэш актуальным? Нужна ли нам кластеризация, и актуализация кэша?
Транзакционный механизм. Как мы будем управлять транзакциями? Вручную или с помощью механизма? Если они оптимистические, то каким образом мы будем определять актуальность версии? А если нам нужно их пересылать за границы сервиса?
Tom>Для разминки сразу вставлю свои 5 копеек — Практически все ORM заставляют пользователя использовать LazyLoad, без него они практически не работоспособны.
Нет. И даже Hibernate этого не требует, хотя предоставляет такие инструментальные средства.
Здравствуйте, Tom, Вы писали:
Tom>Всем привет,
Tom>Хотелось бы в одном месте, например в одном топике собрать все проблемы которые вытекают из обьектно ориентированного способа работы с данными (БД) и использовании ORM средств. Tom>Очень желательны примеры кода!
Tom>Хорошие статьи на эту тему тоже приветствуются.
Tom>Для разминки сразу вставлю свои 5 копеек — Практически все ORM заставляют пользователя использовать LazyLoad, без него они практически не работоспособны.
Tom>Ну и статья так же для разминки Tom>http://blogs.tedneward.com/2006/06/26/The+Vietnam+Of+Computer+Science.aspx
ORM — Object Relational Mapping (-er). Как ни странно, название отражает, как мне кажется, квинтэссенцию ОРМ — это маппинг данных в объекты. То есть грубо говоря, данные из базы (и обратно в базу кстати тоже) у нас поступают в виде, требующем использовать строки (или индексы) для доступа.
var reader = CreateDataReader();
reader.Read();
var value = reader.GetValue(reader.GetOrdinal("Id"));
В то же время ОРМ — это инструмент, который как минимум транслирует эти данные в объекты, позволяющие доступ по именам членов класса. (На полную абстрактность и корректность для всех существующих языков не претендую).
То есть, если вы напишите нечто вроде
// Код 1var reader = CreateDataReader();
reader.Read();
yield return new Product
{
Id = reader.GetInt32(reader.GetOrdinal("Id")),
Name = reader.GetString(reader.GetOrdinal("ProductName")
};
то поздравляю, вы на пути к ОРМ, и написали, строго говоря, маленький "маппер вручную".
Все остальные умные слова, такие как Identity Mapping, Change Tracking, Typed Query Expressions и так далее — это все навороты над простой в сущности идеей: избавить вас от написания кода для перевода данных ридера в данные объекта. И по возможности обратно тоже.
Прежде чем рассматривать все вышеперечисленные навороты, давайте поглядим на Код 1, и увидим самый фундаментальный недостаток ОРМ, который, в лучших традициях диалектики является также и прямым его достоинством: а именно: "используя ОРМ, мы лишаемся свободы и гибкости манипулирования данными, и получаем взамен грубость строготипизированных объектов". Вообще, я считаю, что этот недостаток является фундаментальным только в том случае, если нашим запросам к источнику данных свойственна "горизонтальная изменчивость" — то есть если они могут возвращать резалтсеты с разным количеством и разными именами колонок.
Здравствуйте, Tom, Вы писали:
Tom>Для разминки сразу вставлю свои 5 копеек — Практически все ORM заставляют пользователя использовать LazyLoad, без него они практически не работоспособны. Tom>Ну и статья так же для разминки Tom>http://blogs.tedneward.com/2006/06/26/The+Vietnam+Of+Computer+Science.aspx
Боян в квадрате!!!
Продолжу.
Итак, самый аскетический орм, который можно себе представить — это приведенный в сообщении выше "Код 1", который является по сути тупым копированием данных ридера в данные объекта, выполненным при помощи клавиатуры и рук. На этом этапе ОРМ еще а) не воспринимается как ОРМ, хотя по сути им является б) не вызывает особых возражений также и у противников ОРМ. А также, что немаловажно, по сути ничем не отличается от резалтсета, кроме способа доступа.
Все дальнейшие улучшения можно разделить на фундаментальные улучшения и оптимизирующие улучшения. Из фундаментальных улучшений ОРМ я знаю только одно — это Identity Mapping. Позволю себе напомнить, Identity Mapping — это механизм, который заботится о том, чтобы для каждого значения первичного ключа таблицы объект создавался только один раз.
Насколько важно и существенно это улучшение? Во-первых, оно важно только в случае изменяемых данных. Для immutable данных идентити маппинг не нужен, и достаточно в объекте переопределить Equals и GetHashCode, и избегать ссылочного сравнения.
С введением нами в использование Identity Mapping-а у нас появляется еще одна сущность, которая является бичом ОРМ (как считают его противники) — это контекст. Что такое контекст? Это место для хранения служебных данных, коих ОРМ может плодить немеряно и бесконтрольно. Когда появляется контекст? Когда мы вводим Identity Mapping. Ни одна другая примочка ОРМ не требует обязательного наличия контекста. Изменения можно хранить и в объектах. Ленивая загрузка вообще висит в памяти и ее не нужно хранить вовсе. Но карту идентичности ключей и экземпляров нужно где-то хранить.
Почему появляется необходимость в контексте? И когда она появляется? Появляется она тогда, когда теряется совершенство мира, то есть самодостаточность полученных из датаридера данных. Счастливые пользователи raw db data знают: то, что они извлекают из ридера — это тот минимум, и одновременно максимум, нужный именно сейчас, прямо после вызова. Пользователи ОРМ часто проектируют модель "наперед". Что значит: а) вводят везде где ни попадя навигационный доступ и б) злоупотребляют иерархичностью. Что, кстати, ни в коей мере не является проблемой ОРМ, а является проблемой проектирования модели предметной области. Теперь уже данные, полученные с таким трудом из базы не являются самодостаточными для восстановления объекта по ним. Теперь нам еще нужно восстановить ссылки (хотя из базы приходят только ключи), и агрегированные внутрь коллекции объектов. Почему это плохо? Потому что СУБД "быстрая внутри, и медленная снаружи". То есть быстрее получить за раз 100 записей, чем 10 раз по 10 записей.
И для того, чтобы восстановить дополнительные данные, ОРМ-у приходится дробить запросы. И если с ссылками можно было бы выкрутиться при помощи JOIN-ов, то с иерархиями совсем туго. И пресловутый идентити маппинг и тут вмешивается — в зависимости от сценария использования, иногда выгоднее получать ссылки JOIN-ом, иногда — отдельным запросом.
Теперь о том, чем же плох контекст. Ответ заключается в том, что контекст сам по себе не плох и не хорош, а хороша или плоха связанность восстановленных объектов с контекстом. Причем эта связанность может быть разного рода, и не все они одинаково плохи. В случае Identity Mapping-га контекст хранит в себе ссылку на объект. И для объекта в большинстве случаев это побоку. Значительно хуже получается, когда объект явно или неявно хранит в себе ссылку на контекст. Это может быть вынужденная мера (в случае лейзи лоадинга), или же ленивость разработчиков ОРМ, которые используют базовые классы сущностей, собственные классы коллекций и прочие перлы архитектуры (впрочем, без них иногда не обойтись никак). Особенно весело получается в случае с той же отложенной загрузкой. Так как она в большинстве случаев "прозрачна", то есть пользователь не знает, загружен объект или нет, то можно нарваться на интересную ситуацию, когда контекст уже того, а мы сохранили где-то незагруженный объект. Из-за этого часто вводят такую неестественную операцию, как Detach (англ. — Обрести свободу от Контекста).
Впрочем, Lazy Loading, Changes Tracking — это уже средства оптимизации, которые являются любимым коньком критиканов ОРМ-ов. Особенно достается отложенной загрузке. Почему же вообще появляется такая странная на первый взгляд вещь, как отложенная загрузка. Проблема, опять же, в попытке проектировщиков домена "явно и визуально декларировать связи между объектами". В случае работы с базой по старинке, через ADO.NET, к примеру, попытка "явно декларировать связи" равноценна примерно следующему: если вам нужно сделать запрос к таблице А, то вы в придачу джойните к этой таблице все, что джойнится (это в случае объектов со ссылками на другие объекты), или все, что джойнится плюс все, к чему джойнится (это в случае со ссылками на коллекции объектов). Естественно, что попытка вытащить полбазы одним запросом явно будет нуждаться в оптимизации.
Отложенная загрузка — не такая в общем-то и плохая идея. Плохо то, что скажем в .NET реализовать ее без извращений нельзя. Хуже того, с ней и работать без извратов нельзя. Нужно холить и лелеять контекст, чтобы он не дай бог не умер и не задиспозился раньше объекта.
Однако основное правило оптимизации ленивой загрузки гласит "не надо стараться декларировать все связи без разбору". Впрочем, с развесистыми иерархиями не дружит также сериализация, отдельные виды сериализации вообще не могут работать с отдельными видами связей , а она (сериализация) используется шире, чем ОРМ.
Что касается Change Tracking-а, то это есть попытка а) не делать лишней работы, в данном случае не нагружать базу сохранением неизмененных объектов, и б) избавиться от database-like контракта с методами Add, Update, Delete. Впрочем, от Delete избавиться не удасться. Впрочем, именно change tracking позволяет наибольший простор для оптимизаций и вариаций, и поэтому его редко вспоминают в качестве аргумента против ОРМ.