Как стать автором
Обновить

Комментарии 219

На питончике использовал потому, что нужно было запускать проект на MySQL, PgSQL, Oracle и Sybase. Т.к. Oracle и Sybase у меня не было возможности поставить, то SQL Alchemy отлично подошел. Помимо этого сократил время разработки.

Естественно, если бы я все делал на знакомом мне MySQL, то ORM бы не стал использовать, т.к. многие запросы она делает совсем не логично.
А вот в джанго ORM очень удобный. Но проекты на нем такие большие, как на J2EE, нормально не сделаешь.
НЛО прилетело и опубликовало эту надпись здесь
Банально сложнее и нет практик.
НЛО прилетело и опубликовало эту надпись здесь
Не те практики. К примеру посмотрите Spring Framework. И сравните с django
Ну например в джаве есть EJB, которые созданы изначально для распределенных приложений, которых в джанго нет. Ну и спринг (хотя есть какой-то спринг под питон, но я его не пробовал).
Есть опыт работы с NHibernate, переход на чистый ADO.NET на порядок увеличил производительность. К тому же, при использовании для всяких advanced штук в NHibernate часто вылезают баги и недоделанные реализации драйверов под СУБД. Сам низкоуровневый исходный код явно изначально был сконвертирован из Java, и очень сложен в сопровождении.

Так что в этом смысле, NHibernate годится только для простых проектов.
Возможно, с оригинальным Hibernate ситуация лучше. Но те же lazy-техники с коллекциями в сотни тысяч элементов часто проще реализовать на уровне ADO.NET/JDBC с постраничной подгрузкой.

Любой ORM требует аккуратного обращения. Прежде чем использовать ORM надо уметь делать приложения без его применения.
Так никто не спорит. Я просто привел конкретный пример, когда прямая работа с СУБД выгоднее использования ORM. Каждому свое, все зависит от задачи.
В хорошем ORM есть средства для работы напрямую с СУБД ;)
ага, только в этом случае нет необходимости в ORM ;)
Не сказал бы. К примеру если у вас используется MVC для web-приложения, то лучше как раз использовать ORM, а там где это уже не оправдывает себя использовать чистый SQL.
Не спорю. Я уже выше писал, что все зависит от задачи. В данном конкретном случае запуск SQL-скрипта через ORM ничем не лучше исполнения запроса напрямую. Опять же, по опыту с NHibernate даже здесь заметна разница в производительности (раза в два), видимо выполняется какая-то пред- или постобработка.

Кстати, есть такая интересная штука — MyBatis (раньше назывался iBatis). Это не совсем ORM в традиционном понимании. И производительность в нем вроде практически эквивалентна прямому исполнению SQL (разумеется, при сравнении с ручной генерацией объектов). Он просто позволяет с помощью XML-конфигурационных файлов вынести скрипты INSERT/UPDATE/DELETE, написать интерфейсы объектов и MyBatis сам их замаппит. Получается такая легковесная ORM. Есть под .NET и Java. Подробнее: www.mybatis.org/
Я предпочитаю использовать JPA :) Там разницы нет особой. MyBatis я видел, не сказал бы что особо хорошо при сложной базе.
JPA это стандарт… а реализаций этого стандарта несколько… например хибернейт его вполне поддерживает…
Я бы даже сказал больше. JPA это стандарт, набор интерфейсов. Он отстает по развитию от Hibernate, и по сути пишется с него. Поэтому это наиболее распространенная реализация. Хотя в последнее время уже появляются и другие реализации, да.
Черт знает с чего он там пишется, но у него есть один не маловажный плюс. Он декларативный и второй версией пользоваться удобно. У первой версии были кое-какие неудобные ограничения, но в двойке их уже нет.
Я использую EclipseLink
Или вы свою реализацию JPA имели ввиду? Тогда извините…
MVC это чисто UI часть, ORM — это доступ к данным и по наличию MVC определять необходимость ORM — весьма странная затея. ))
M — в MVC это model. А он к ORM имеет отношение.
Модель в рамках MVC, не имеет никакого отношения к ORM.

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

Если уж говорить про то, когда выгоднее всего использовать ORM, с точки зрения архитектуры приложения, то скорее всего вы замете связь между реализацией слоя бизнес логики по паттерну доменная модель и технологией ORM. Вот тут, при реализации такого подхода, плюсы ORM очевидны.
Не накладывает, но удобнее использовать там именно ORM.
Может быть вы про конкретно Asp.Net MVC?

Если про паттерн в целом, то не соглашусь. Хотя нет, соглашусь, но из за того, что ORM всегда удобнее использовать и дело не в MVC паттерне. :)
Не я не про него :) Именно что всегда удобнее использовать :] А удобнее из-за того что обычно ООП :]
Все вы хотите что то к ORM притянуть за хвост. Зачем?

Ну ООП? И что? Т.е. вы подразумеваете что если ООП то полюбому ORM удобнее использовать? Ну че за бред то? :(

Вы ищите какое то золотое объяснение использования ORM. Не надо. Поймите чем хороша технология сама по себе. Что она дает по сравнению с другими (вот тут сейчас важно) ПОДОБНЫМИ технлогиями, которые решают туже задачу. И выясните с помощью какой технологии вам удобнее решать эту задачу. Но не тяните сюда какие то бессмысленные объяснения.
Все вы хотите что то к ORM притянуть за хвост. Зачем?

Там где это удобно это надо делать.

Т.е. вы подразумеваете что если ООП то полюбому ORM удобнее использовать? Ну че за бред то? :(

Если вы работаете с MVC в ООП среде, то обычно Model это объект или коллекция объектов. В случае если вы не хотите ничего ломать у вас где-то возникнет хоть какой-то примитивный ORM который будет маппить данные из базы в объекты и обратно.

Вы ищите какое то золотое объяснение использования ORM. Не надо. Поймите чем хороша технология сама по себе.

Я использую технологии только там где они приносят profit, если они его не приносят я его там не использую.
Там где это удобно это надо делать.


Там где удобно тащить за хвост, надо тащить за хвост? :) Я тут говорил не про применимость ORM, а про ваше объяснение причин использования ORM. Объяснения, которые вы тяните за хвост.

Если вы работаете с MVC в ООП среде, то обычно Model это объект или коллекция объектов. В случае если вы не хотите ничего ломать у вас где-то возникнет хоть какой-то примитивный ORM который будет маппить данные из базы в объекты и обратно.


Уважаемый, хочу подчеркнуть что я сторонник ORM. Я часто использую ORM. Но причины этого не использование MVC + ООП. Поймите что здесь нет связи.

Я могу разрабатывать приложение с использованием MVC + ООП, без использования ORM и не надо будет ничего ломать. Вообще ничего. Будет полноценный MVC. И я буду использовать ООП где захочу (если честно я вообще не понимаю зачем вы ООП притянули сюда).

Я использую технологии только там где они приносят profit, если они его не приносят я его там не использую.


Вы немного вытащили мои высказывания из контекста. Безусловно нужен profit. Ток этот profit вы сможете выяснить ток в том случае, если знакомы с другими технологиями. Именно это я и говорил.
Я тут говорил не про применимость ORM, а про ваше объяснение причин использования ORM. Объяснения, которые вы тяните за хвост.

Вообще я проводил причины почему стоит это делать. Если вас они не устраивают вы можете и не использовать.

Но причины этого не использование MVC + ООП. Поймите что здесь нет связи.

Не делайте не верных выводов. Я сказал только что в MVC удобно использовать ORM в силу того что MVC применяется чаще всего вместе с ООП и M чаще всего представлен как объект или коллекция объектов. А вы тут напридумывали что я из-за MVC использую ORM.

Не делайте не верных выводов. Я сказал только что в MVC удобно использовать ORM в силу того что MVC применяется чаще всего вместе с ООП и M чаще всего представлен как объект или коллекция объектов. А вы тут напридумывали что я из-за MVC использую ORM.

К примеру если у вас используется MVC для web-приложения, то лучше как раз использовать ORM

Извините, но из ваших слов у меня складывается именно такое представление.

Если вы имели ввиду что то другое, приношу свои извинения. :)

И все таки, в рамках MVC, даже с использованием ООП :), модель чаще всего объект или коллекция объектов, не из за того что используется ООП в рамках MVC. :) А из за того, что при построении бизнес логики очень хорошо зарекомендовал себя паттерн DomainModel (по Фаулеру). Вот ЭТА штука, очень хорошо ложится на ORM.
Кому как. Мне в последнее время удобно использовать ODM (Object Document Mapping), а не ORM, особенно когда работаю с документоориентированными СУБД, а не реляционными :)
Да, согласен, кому как.

Вы кстати какие СУБД документоориентированные используете? И на чем у вас клиент? Просто интересно. Тут знакомые мне хвастатлись про одну СУБД такую, интересно ваше мнение.
MongoDB выбрал, но в принципе чисто из-за того, что ODM для неё «от Doctrine» в beta3, а не alpha1 стадии как для CouchDB :) Переход не исключаю, и даже чуть ли не в планах, сама Кауч по идеологии нравится больше.

Клиент на html5 :) Апп сервер на php (Смотрел другие варианты, но преимуществ, оправдывающих серьёзное изучение других технологий при поверхностном не обнаружил, на PHP напишу быстрее. Была бы РСУБД — были бы варианты, а с документоориентированными инструментами ориентированными на отсутствие схемы БД как-то везде плохо, особенно в статических языках, но задачи типа «создание пользовательских объектов (и их типов даже) с произвольным количеством и типов атрибутов, включая составные» на реляционную модель как-то плохо ложатся).
Спасибо! Мне кстати знакомые как раз про MongoDB говорили. :)

За клиента на HTML5 респект! У нас пока ток в планах, далеких. Ждем новой винды и будем смотреть чего там MS сделает с Silverlight + WPF. Правда ли на HTML5 + JS перейдет. Если перейдет, то бум думать. :)
>MVC это чист UI часть

Более бредового высказывания про MVC не слышал. :)
Да, NHibernate это и есть порт ява-версии на .NET, разумеется.

Насчет коллекций в сотни тысяч элементов… Тут я весьма скептичен вообще.

Если вам реально нужно вытаскивать такие объъмы на клиента, то вытаскивать их в одну коллекцию сразу целиком в память нельзя, т.к. может запросто быть OOM или просто будет отъедено непозволительно много памяти. В таком случае лучше использовать streaming и передавать данные из курсора (result-set-a) порциями фиксированного размера сразу туда, куда нужно.

Так же, в реальности, если вам это нужно для какой-то сложной аналитики, обычно куда проще пре-агрегировать эти данные на уровне СУБД в какой-то временной таблице или materialized view, и использовать дальше в рассчетах, тащить их все на промежуточной слой далеко не всегда нужно.

О том и речь. Трудно себе представить, чтобы пользователю реально нужно было просмотреть все сто тысяч. Но выводить Grid с таким количеством элементов на уровне хранилища — такая задача часто встречается. Пользователю удобно выполнять сортировку, фильтрацию, скроллинг по всем данным. Но вот на клиент нужно подгружать только страницу отображаемых в данный момент данных. Т.е. у пользователя на уровне интерфейса создается полная иллюзия работы с огромной коллекцией. А по факту выполняется подгрузка/выгрузка данных в режиме on demand.

Для таких задач ORM неприменим, либо наблюдается серьезный проигрыш в производительности/памяти.
а в чем проблема подгружать нужные страницы через ORM?
Не все ORM умеют и не все знают что так можно :)
«Для таких задач ORM неприменим»
Да что вы говорите???

Именно для подобных сценариев в том же Nhibernate поддерживается кэш первого и второго уровня, продвинутый lazy-loading и масса других пирожков.

Любая серьезная ORM обязана уметь как минимум lazy-load-ить, и загружать данные постранично.
В теории оно все так. На практике конкретно в NHibernate lazy-loading коллекций реализован не так уж хорошо в плане производительности и используемой памяти. Ну и опять же, для построения Grid'а с сортировкой по разным столбцам коллекции не подходят (хотя да, подходит исполнение запросов на hql), но там опять же вылазят эти lazy-коллекции. Возможно, в других «серьезных ORM» ситуация лучше.
NHibernate годится для конкретных штук. В частности, и Ayende не раз об этом упоминал — OLTP-сценарии. Народ часто начинает гнать на NH, попытавшись использовать его для ETL (batch processing) или OLAP.

Насчет того, что только для простых проектов — не соглашусь.
Ниже уже писали в комментах, что ORM проявляет себя лучше всего при не очень сложной структуре данных и не очень больших объемах данных, подтягиваемых «за раз». Когда основная трудоемкость в бизнес-логике, накрученной над этими данными. При этом сами проекты могут быть очень и очень сложными.
ORM выгодно использовать в случае если приложение заточено под работу оператора с объектами от одного до десяти. Проще говоря нет никаких яростных табличных интерфейсов и требуется достаточно сложная логика при обработки объекта. А такой класс приложений очень велик и это подавляющее большинство веб-приложений.
Я и не думал, что мой вопрос так всбудоражит.
Просто это очень старый срач «ORM vs pure SQL», но видимо о нем все забыли. Я еще года 3 назад попадал в подобные даже чаще, чем в срачи про РНР. Эта тема вбрасывает так же как «зачем Linux на десктопе», только если второе уже всех достало, про ORM давно все забыли и можно посраться заново.

Думаю краткое содержание предыдущих серий вам рассказывать не надо, в комментариях к вашему вопросу можно встретить все типичные ответы обоих сторон для подобного срача. Остальные читайте там ↓
Недавно прочел ORM is an anti-pattern мнения автора статьи в чем-то пересекается с вашим. Вкратце плюсы-минусы:
1. ORM проще понять, чем SQL (можно и не знать SQL если использовать ORM)
2. Он эффективен на ранних стадиях (по быстренькому чего-нить написать)
3. Если приложение усложняется, то все плюсы ORM гаснут — приходиться учить SQL, дописывать…
4. 20+% проектов ломают абстракцию ORM
5. Объекты — это не адекватный способ представления реляционной структуры
6. Если ваши данные — объект, то лучше использовать NoSQL-решения
7. Из-за реляционной природы появляются накладные расходы при создании объекта

Почитайте, достаточно интересное мнение + интересные отзывы в коментах
ORM проще понять, чем SQL (можно и не знать SQL если использовать ORM)

Отправлять изучать SQL. Никакого ORM пока нет понимания во что он транслирует и как. Иначе такие чудеса будут…

Он эффективен на ранних стадиях (по быстренькому чего-нить написать)

Как я уже говорил он эффективен когда у вас мало данных много действий.

Если приложение усложняется, то все плюсы ORM гаснут — приходиться учить SQL, дописывать…

См. ответ на пункт один :)

Объекты — это не адекватный способ представления реляционной структуры

Генерация объектов ORM должна идти от таблиц в базе, а не наоборот. В этом случае этой проблемы у вас не возникнет. В любом случае умеет или не умеет это ORM сначала должна быть спроектирована схема базы. А уже потом на ее основе созданы объекты. Это залог жизнеспособности решения.

Если ваши данные — объект, то лучше использовать NoSQL-решения

Кто вам сказал что это лучше? Оно лучше на очень малом спектре задач.

Из-за реляционной природы появляются накладные расходы при создании объекта

Кеширование объектов спасает :)
Во многом я с вами согласен. Те пункты — это выдержки из статьи и с какими-то из них можно согласиться, да и просто интересно мнение «другой стороны».

ORM это абстракция/инкапсуляция т.е. теоретически можно инкапсулировать как SQL так и NoSQL и не знать ни один из них, однозначно нельзя сказать будет ли лучше со знанием основ или нет. Например, вы можете не знать как устроена машина, но водить можете. Если вы будете изучать строение авто, то не известно поможет ли вам сэкономить деньги, скажем, на починке, то потраченное на изучение время.

«Как я уже говорил он эффективен когда у вас мало данных много действий» — безусловно.

«Кто вам сказал что это лучше? Оно лучше на очень малом спектре задач.» — момент спорный. Можно мыслить реляционно и тогда реляционная БД в большинстве случаев будет для вас лучше, а можно мыслить документами, тогда мнение может измениться. Я ни в коем случае не говорю, что NoSQL > SQL.

«Кеширование объектов спасает» — вы предлагаете обход/маскировку проблемы :)
Можно мыслить реляционно и тогда реляционная БД в большинстве случаев будет для вас лучше, а можно мыслить документами, тогда мнение может измениться. Я ни в коем случае не говорю, что NoSQL > SQL.

Основное больное место NoSQL это агрегация. Как только надо что-то из хранимого обработать агрегативно и тут что называется приплыли. Реляционная модель во многих случаях лучше и дает большую производительность. И что самое главное можно дать оценку производительности. В случае NoSQL это не всегда так, да и правильное его применение сложнее.

вы предлагаете обход/маскировку проблемы

Оно работает :)
>> Отправлять изучать SQL. Никакого ORM пока нет понимания во что он транслирует и как. Иначе такие чудеса будут…

т.е. прежде чем писать на C# надо изучить IL!
Вообще изучение любого низкоуровневого языка полезно, для понимания что же там будет на выходе. Но в случае ORM совершенство трансляции существенно ниже. Из-за этого надо учитывать особенности работы СУБД и не делать выборки вида select * from из двух таблиц чтобы что-то посчитать. А такие ошибки на уровне ORM делаются на раз.
я с вами согласен, более того, вы говорите очевидные вещи. Просто вставил ироничную аналогию.
Генерация объектов ORM должна идти от таблиц в базе, а не наоборот.

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

Замечу, что подход, где приложение первично, заметно выигрывает по простоте разработки и надежности.
Все зависит от точки зрения — строим базу данных для приложения, или приложение для базы данных.

Еще раз напоминаю реляционная модель беднее чем объектная.

Замечу, что подход, где приложение первично, заметно выигрывает по простоте разработки и надежности.

Только пока у вас простая модель данных. Как только у вас в базе будет больше 20-30 таблиц этот подход будет проигрывать. Особенно если у вас будет много данных. Вы можете не соглашаться, но это так.
Спор на тему что использовать: DatabaseFirst\CodeFirst. В первую очередь зависит от самой ORM, и что она позволяет делать. Поэтому про сложность использование того или иного подхода, следует отнести к богатству/бедности той или иной ORM реализации.

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

А вообще спор на тему SQL or ORM. ;) Всегда поражался широте спора хабражителей. :)

Спор на тему что использовать: DatabaseFirst\CodeFirst.

Очень часто те кто использует ORM и CodeFirst пишут приложение большая часть логики направлена на работу с СУБД. А это проводит к плачевным последствиям.
Не вижу зависимости. CodeFirst и логика работы с СУБД не вяжется у мну. Раскройте пожалуйста.
К примеру у вас есть приложение обладающее сложной структурой данных. К примеру биллинг. Если вы начнете сначала писать код, а потом с нее генерить базу у вас будет ад и израиль.
Это у вас будет ад и израиль. А у меня, с использованием EF и головы, будет все ок. И не один большой проект писали через CodeFirst. Живы и здоровы.

Безусловно проблемы есть всегда. Но скорее проблемы технологии, а не подхода.
ER-диаграмму предварительно рисуете или нет? :)
А какое это имеет отношение к тому, что из чего генерируется, что я использую CodeFirst или DatabaseFirst? Вы хотите сказать что я заведомо подразумеваю что это все будет ложиться на реляционное отображение? Так вот, конечно я это подразумеваю, и буду проектировать свою доменную модель так, что бы ее можно было замаппить без последствий на реляционное отображение. И если вы думаете что кто то начнет использовать по максимуму наследование и полиморфизм, то вы ошибаетесь. И если даже кто то начнет, то проблема не в подходе CodeFirst, а проблема в не знании технологий.

Тут вопрос понимания технологии играет роль. И если человек знает что такое ORM, он не встретит никаких проблем при использовании подхода CodeFirst.

А ER иногда рисуем, иногда нет. Иногда рисуем диаграммы классов, иногда нет. Иногда используем еще что то. Но проблем в подходе CodeFirst, не более чем в любом другом.
А какое это имеет отношение к тому, что из чего генерируется, что я
использую CodeFirst или DatabaseFirst?

Прямое. ER-диаграмма это результат проектирования базы данных. Если она у вас есть, то разницы от entities генерить таблицы или entities генерить от таблиц нет. Это только метод генерации уже готового проекта базы. И в этом случае это не CodeFirst.

Вы хотите сказать что я заведомо подразумеваю что это все будет ложиться на реляционное отображение? Так вот, конечно я это подразумеваю, и буду проектировать свою доменную модель так, что бы ее можно было замаппить без последствий на реляционное отображение.

Это и есть DatabaseFirst. Я под CodeFirst подразумеваю подход когда народ колбасит декомпозицию предметной области сначала в ООП, а потом уже как-то пытается это упихнуть в базу.

Тут вопрос понимания технологии играет роль. И если человек знает что такое ORM, он не встретит никаких проблем при использовании подхода CodeFirst.

Если он знает что такое ORM он знает какие на нее накладывает ограничение реляционная модель. И как факт он приходит к проектированию базы данных, если она достаточно сложна и требует такого проектирования.
Это и есть DatabaseFirst. Я под CodeFirst подразумеваю подход когда народ колбасит декомпозицию предметной области сначала в ООП, а потом уже как-то пытается это упихнуть в базу.


У нас с вами разное понятие CodeFirst. В моем понимании это не имеет никакого отношения к проектированию системы.

Это один из подходов при работе с ORM. Не более того. Если кто то «наколбасит» декомпозицию предметной области через ООП, с использованием наследования и полиморфизма, то это его непонимание технологий ORM и что это такое. Но это не минус подхода CodeFirst.

При этом подходе вы просто генерируете БД по вашим классам, т.е. сначала описываете в коде ваши классы которые будут маппится на БД и по которым БД будет генерироваться. Конечно ваши зависимости должны ложится на реляционное представление.
Вот поэтому ваши слова:
Генерация объектов ORM должна идти от таблиц в базе, а не наоборот.

Абсолютно не имеют под собой почвы.

Вы затронули тему генерации классов по БД. Что есть подход DatabaseFirst. Когда по классам генерируется БД — CodeFirst. И там и там необходимо поддерживать реляционное представление. И проблемы тут не в том что люди не умеют использовать CodeFirst. Проблемы в том что люди не понимают что такое ORM.
А подход, когда описывается предметная область через «наследование и полиморфизм», а потом выбирается лучше она ляжет на реляционную модель, или, скажем на key-value (а то и часть туда, часть туда, а часть вообще на файлах), ничем себя не оправдывает?
Вы сейчас в принципе о тех случаях когда удобнее создать сначала объектную модель? Да, вы правы, такой подход оправдывает себя.

Но это не есть CodeFirst, при использовании ORM. И я думаю что вы сейчас и не имели его ввиду.
Частично имел, то есть я пишу сначала классы, а потом когда вижу, что часть (или все) из них хорошо ложатся на реляционную модель, то генерирую по ним таблицы (возможно предварительно чуть изменяя эти классы, чтобы ложились ещё лучше). Но при разработке модели возможность использования ORM (да и вообще РСУБД) держу в уме только как одну из потенциально возможных, стараясь преждевременно к ней не привязываться. Когда решу, что хранилищем будет только РСУБД, тогда часть классов ляжет на неё через ORM без переделки, часть с незначительной, а часть, возможно, придётся сильно изменить. Но в любом случае таблицы буду генерировать по классам :)
Понял. Но так я еще не пробовал. :) Обычно сразу стараюсь решить что будет выступать в роли хранилища. Но если не буду уверен, то буду делать точно также. :)
Сложно решить заранее, когда толком не знаешь, что в итоге должно получиться. Кажется это называется «Agile development» :)
У нас, у дотнечтиков, настолько аджальный Agile не прижился. :) :)
И что за «часть логики, которая направлена на работу с СУБД». Что это такое и почему оно приводит к печальным последствиям?
Макросы подходят лишь для использования небольших возможностей СУБД, у которых синтаксис различается довольно слабо. Например, это может быть что-то вроде следующего (для поддержки MS SQL и Sybase в одном приложении, где все основные тонкости языка могут уместиться в макросах)
#M_FORCEPLAN
select ...
from table1 #M_NOLOCK_INDEX (XPkTable1)
inner join table2 #M_NOLOCK_INDEX (XpkTable2)
on ...
where ...
#M_FORCEORDER


Т.е. тут мы может использовать четко указанные индексы и строго определенную последовательность соединения таблиц. Внешне достаточно понятно. Но, чрезмерное усложнение количества возможных макросов очень отрицательно сказывается на качестве кода. Его потом очень трудно понять или еще хуже, не знания «во что превращается макрос на данной СУБД» приведет к неправильному и неоптимизированному запросу.
Rails–разработчики смотрят на этот топик с умилением :)
НЛО прилетело и опубликовало эту надпись здесь
Я редко встречался с Java, часто посещаю конференции .net'чиков, так вот от NHibernate отличий просто миллион. Главное приемущество (и проблема) в самом Руби: он позволяет делать безумное метапрограммирование, но цена тому — скорость.

Если не сранивать скорость работы, то NHibernate — это ActiveRecord из Rails, сделанный будто бы лет 20 назад.

Ассоциации, валидации, миграции — все это есть. Адаптеры для различных бд тоже. Настроенные из коробки 3 окружения (development, test, production), для каждого из них создается своя база данных.

Откройте ссылку: gist.github.com/1062185

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

Далее смотрим на файл миграции, которая только что создалась: вторая врезка. Есть 2 метода: up и down. Первый вызывается, когда вы «накатываете» миграции командой консоли rake db:migrate, вторая выполняется, когда «откатываете»: rake db:migrate. Уже в заготовке мы видим, что описано создание таблицы users (модель User — таблица users). В down уже прописано, что при откате миграции эту таблицу нужно удалить. Допишем туда пару своих полей: третья врезка. Мы добавляем 2 строковых поля (login и password) и указываем, что они не могут принимать значение null. И плюс одно булево поле (active), которое по умолчанию ставится в false.

После этого в консоли нужно вызвать rake db:migrate и наша миграция «накатится» (если у вас уже создана бд, которая создается командой rake db:create согласно настройкам, прописанным в конфиге по умолчанию). Увидите то, что находится в следующей врезке.

Если сейчас проект скачает другой разработчик, ему потребуется всего лишь выполнить миграции, а не выискивать полдня, каких же полей у него не хватает в базе.

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

Можно зайти в rails-console (rails console или rails c) и создать нового юзера, допустим. Консоль идентична обычному рельсо–приложению, в ней можно делать те же действия. В следующей врезке то, что можно теперь делать (даалеко не полный список).

В следующей врезке — тоже милые вещи.
> NHibernate — это ActiveRecord из Rails, сделанный будто бы лет 20 назад.

Это фактическая ошибка. NHibernate реализует сложный набор паттернов: Data Mapper, Identity Map, Unit of Work.
ActiveRecord в свою очередь реализует паттерн Active Record, который является одним из самых простых вариантов реализации ORM, и даже нарушает SRP (принцип единственной ответственности) для сохранения максимальной простоты.
И хоть я сам сейчас программирую преимущественно на Ruby, мне кажется, не очень этично глумиться над людьми, которые в силу специфики своих проектов вынуждены использовать более сложное решение на основе Data Mapper, а не простенькое на основе Active Record.

P.S. На всякий случай упомяну, что паттерн Active Record реализован для всех популярных языков, а не только для Ruby.
Так что принципиальные отличия в паттернах «Data Mapper vs Active Record», а не в Rails. Одно из ключевых отличий состоит в том, что Data Mapper создаёт объекты на основе произвольного набора данных из базы данных, а Active Record на основе одной единственной таблицы в базе данных.

P.P.S. Миграции к ORM вообще никакого отношения не имеют, они относятся к вопросу создания и редактирования схемы базы данных, а не к вопросу преобразования отношений в объекты.
Меня попросили показать, как и что умеет ActiveRecord в рельсах, я показал.
Про 20 лет — просто наблюдение человека, смотрящего со стороны. Такое все жалкое, недоделанное (Entity Framework, Fluent) и тд.

Я не то, чтобы смеюсь или глумлюсь, Руби озадачивает скоростью, этого достаточно, чтобы во многих нишах о нем даже не вспоминать.

И да, я не видел ни одного крупного проекта, написанного на руби/рельсах с помощью DataMapper'a вместо AR.
Меня попросили показать, как и что умеет ActiveRecord в рельсах, я показал.
Мне показалось, что там было всего пару слов про ActiveRecord, всё остальное — про генераторы кода, миграции и прочие приятности, не имеющие ни малейшего отношения к ORM.

Про 20 лет — просто наблюдение человека, смотрящего со стороны. Такое все жалкое, недоделанное (Entity Framework, Fluent) и тд.
Почитайте Фаулера «Patterns of Enterprise Application Architecture», Active Record ничуть не современнее, чем Data Mapper. Если вы не понимаете смысла незнакомого паттерна, это ещё не значит, что его реализация «жалкая и недоделанная», просто паттерн призван решать задачу по другому и ожидать что NHibernate, реализующий Data Mapper, когда-либо станет похож на Active Record из Rails (а видимо именно по мере похожести определяется доделанность в вашем случае) по меньшей мере очень странно.

Руби озадачивает скоростью, этого достаточно, чтобы во многих нишах о нем даже не вспоминать.
Ну причём тут скорость, мы тут что вообще обсуждаем архитектурные решения или синтетические тесты, результаты которых ничего не значат в реальном мире.

И да, я не видел ни одного крупного проекта, написанного на руби/рельсах с помощью DataMapper'a вместо AR.
А уверен, что видел код всех крупных проектов на руби?
А если серьёзно, существующая для Ruby реализация паттерна Data Mapper, с одноимённым названием, сильно упрощённая и по сути похожа на ActiveRecord под другим углом. О существовании готовых решений уровня Hibernate под Ruby мне не известно.
Я никого (совершенно никого) не хотел обидеть своим комментарием и мне очень жаль, что я таки обидел или задел за живое тех, кто использует H или NH.

Я сравниваю не DataMapper и ActiveRecord, я сравниваю скорость разработки и удобство разработки двух схожих по функциональности продуктов, основываясь на своем опыте в Rails и чужом — в Hibernate и NHibernate.

По поводу миграций, я сравниваю, опять-таки, не паттерны из книжки, а два реально существующих проекта (библиотеки, называйте как угодно), призванные упрощать жизнь программистам.

По поводу скорости — это наоборот камень в огород Ruby (не только ведь расхваливать его можно, верно?).

Но, видимо, я таки задел за живое любителей H и NH, поэтому живым мне отсюда уже не выйти :) Я не хотел, честное слово. У каждой платформы и технологии есть свои плюсы и минусы.
NHibernate намного сложнее, чем Rails AR, и много более функционален и главное — охватывает куда большее количество подходов. Включая возможность написания на нем реализации паттерна Table Module (Active Record). Пример — Castle AR.

И у него совсем другое применение. Однако, я бы не был столь категоричен, чтобы отодвигать NH только в нишу «совсем тяжелого энтерпрайза», но, признаюсь, меня и самого напрягает стиль работы с NH (хотя FluentNHibernate и делает жизнь значительно легче).

NH совершенно точно не предназначен для быстрой разработки аля Rails AR, и поэтому их вообще некорректно сравнивать. С NH можно разрабатывать вещи и быстро, но его изучение требует времени. У AR, и вообще Rails — другой стиль, который мне самому ближе.

В последних проектах я отошел от NH и от ORM в целом, пытаясь использовать другие подходы. В них, кстати, AR более применим, нежели NH.

И еще — про 20 лет я бы не говорил — NH очень даже современен в своей функциональности, просто у него другой стиль.
Мне сложно говорить о H и NH, потому что я на них никогда ничего не писал. Но вот на прошлой неделе я был на слете дотнетчиков и слушал доклад о Fluent. Вроде как упрощает жизнь, крутая такая штука, но… очень (ОЧЕНЬ) много вещей нужно писать руками. В Rails есть конвенции, в Fluent почти что тоже есть, но их как бы и нет вовсе.

Зачем мне каждый раз руками задавать название таблицы для Entity? В рельсах с самого начала был класс Inflector (или как-то так), который отвечает за склонения английских слов: он не такой сложный, этот класс. Почему в 21 веке я вообще должен об этом париться?

Отошел от конвенции — указал название руками, не отошел — да с какой стати мне из проекта в проект, из модели в модель писать одно и то же?

И это — только мааленький пример того, почему я написал про 20 лет. H и NH не плохие (я этого и не говорил никогда), но Рельсы (в целом) более человечны, что ли. Все для людей, ну вы и сами знаете :)
Я согласен совершенно по поводу конвенций. Я целиком и полностью за такой подход. И за простоту Rails. Именно что — не писать тривиального boiler-plate-кода. Это бесит и раздражает :) Ну, вы это и так понимаете.

Но про 20 лет я все равно не стал бы говорить, ибо не так уж много вообще API написано с принципом Convention over Configuration в голове. Т. е., если он не преследуется — вовсе не значит, что технология сразу допотопная.
В NH chaining сделали совсем недавно, если я не ошибаюсь. До этого делать его было нельзя. То есть всякие рельсовые Post.recent.popular.limit(10) сделать было нельзя, что удручает. Насчет наличия named_scope я тоже не уверен. Валидации — не уверен. Ок, не 20 лет, пусть поменьше, но не в ногу со временем.
Валидаторов в .NET хватает. Я бы не стал напрямую сравнивать Rails AR и NH — они слишком уж разные по архитектуре.

Насчет named_scope — я не в курсе, что это такое :)

Ну а насчет «Post.recent.popular.limit(10)» — есть LINQ, и у NH есть какой-никакой LINQ-провайдер. Получается что-то вроде Data.FindAll<Post>().Where(IsPopular).Paginate(10).
named_scope — это когда я в модельке описываю один раз некое recent (например, граница по дате добавления), а потом где угодно в проекте указываю Post.recent — выберет все посты с заданными (один раз и в одном месте) условиями.

Аа, или это мне как раз про LINQ новый говорили, что вот в нем как раз это появилось. Ну, в общем я не против NH, но таки Rails AR мне кажется более продвинутым. Опять же, я напомню всем про скорость работы.
Понял про named_scope. Хорошая вещь. Разумеется, это делается и в .NET, обычно с помощью паттернов Specification или QueryObject (но можно и расширением к Repository). Задается в одном месте — это однозначно, DRY — иначе никак.
По поводу ассоциаций еще немного. Поддерживаются все типы ассоциация, рассмотрим ассоциацию один-ко-многим:

Создадим еще одну модель (Post) и укажем, и добавим в таблицу posts (по аналогии с пользователями) 1 поле: заголовок (например) и еще int'овое поле user_id. Опять выполним миграции, пропишем 2 строки кода и получим полностью рабочие ассоциации.

В файле модели user.rb нужно (между class и end) написать has_many :posts, :dependent => :destroy, а у поста — наоборот belongs_to :user.

Теперь если мы удалим юзера, удалятся все его посты (dependent можно не указывать, тогда не удалятся). После этого можно делать такие вещи:

user = User.create(:login => "login", :password => "password")
user.posts — тут будет пустой массив, у юзера нету постов
user.posts.create(:title => "first post")
user.posts.count — вернет 1, у юзера есть 1 пост
user.posts.first.title — вернет заголовок первого поста
user.posts.first.user — вернет то же, что и user.

Post.create(:title => "second post", :user_id => user.id)
Post.create(:title => "third post", :user => user)

post = Post.new(:title => "fourth post")
post.user = user
post.save!



И так далее. Можно настраивать валидации и вообще все, что душе угодно.
В файле модели user.rb нужно (между class и end) написать has_many :posts, :dependent => :destroy, а у поста — наоборот belongs_to :user.

Теперь если мы удалим юзера, удалятся все его посты (dependent можно не указывать, тогда не удалятся)

Управление ссылочной целостностью данных на уровне приложения — это не та вещь, которой стоит гордиться… А вот задать нормальные foreign keys на уровне БД в Rails, к сожалению, до сих пор довольно сложно, если не использовать raw SQL под конкретную СУБД, особенно «из коробки».
… а еще хранимые процедуры и триггеры, да побольше, побольше. давайте по всему серверу размажем бизнес–логику одного-единственного приложения, а?

Ну, половина бизнес–логики будет храниться в моделях, другая половина — в хранимых процедурах, вот только… при установке приложения на другой сервер, вы скорее всего устанете (я — так точно устану) переносить все это, вместо просто обычного скачивания исходного кода приложения и запуска.

А уж если переезжать на другую базу (c Mysql на Postgres, например) — вот вообще веселье начнется.
Ваша логика понятна, и полностью применима к маленьким веб-проектам.

К крупным проектам, как я указал в посте, это мало применимо, ибо есть масса сложной аналитики, которая на реляционную модель ложится куда лучше + Enterprise-СУБД поддерживают как правило из коробки очень многие аналитические функции.

Про перенос приложения на другой сервер — это отдельная история.

Вам надо с нуля развернуть приложение на новом сервере? Отлично, у вас есть инсталлятор, который создает схему БД, раззиповывает JBoss, подкладывает под него нужные библиотеки и ваше приложение — все готово.

Вам нужно применить патч на существующий сервер? Обновить его до следующей версии?

Патч состоит из двух частей — миграционный скрипт СУБД, собранный с помощью TOAD или других инструментов и тщательно проревьювленный, и патч код промежуточного уровня (Java классы, ресурсы, client-side code).

Да, и то и другое требует определенного времени и усилий (правда автоматизируемо — например, у нас есть самописные инструменты для установки приложения или апдейтов на кластер, конфигурация которого (адреса узлов и их роли) задана декларативно). Но так живет крупный Enterprise :)
Я ниже написал, да, что конкретно к данной статье Rails не к месту, ибо не тот уровень.
Да почему не тот уровень? Rails вполне успешно применяется для крупных веб-проектов. Говорите за себя, а не за Rails в целом.
Крупных — да.
Мне всегда казалось, что Enterprise — это немного бОльшее, чем просто «крупный». На более менее крупных я и сам работал, я говорю именно об Enterprise.

Крупные банковские системы, прочие вещи, связанные со стабильностью, надежностью и деньгами. Я _не_ против Rails, я кроме них ничего и не умею толком, но я отчетливо понимаю, что все это — не их стихия. Но написать, понятное дело, можно все что угодно.
Я, наверно, вас сильно удивлю, но бывают случаи когда от хранимых процедур никуда не денешься и это реальная необходимость для Rails-проекта.
Что касается, обеспечения ссылочной целостности, то это задача СУБД и лучше уж реализовать её и в ключах и в моделях, чем только в моделях и потом получать пачками «NoMethodError: undefined method `xxx' for nil:NilClass».
По поводу хранимых процедур хотелось бы пример. Возможно, и мне стоит их использовать, а я и не в курсе. Заранее спасибо.
По поводу целостности: я писал выше, что очень хорошо в миграциях прописывать :null => false для полей, где null недопустим. Этот параметр сохраняется именно в СУБД, а не в модели, и он очень полезен. Именно чтобы сразу видеть, что где-то что-то пошло не так.

Просто я немного против того, чтобы логику размазывать по всему серверу, как-то это нелогично.
НЛО прилетело и опубликовало эту надпись здесь
Спасибо, я знаю про плагин, поэтому и написал «из коробки», вообще логично было бы включить эту функциональность в Rails.

> Но вообще говоря, в рельсах есть штуки, на которые люди, умеющие готовить sql, смотрят с презрением.

Ну такие штуки есть в любом ORM, именно поэтому надо понимать как конкретный ORM работает и какие запросы он генерирует за кадром, иначе такой фигни можно понаписать…
А вообще Active Record в Rails очень прилично реализован, ему бы ещё поддержку DISTINCT получше сделать и вообще шикарно будет :-)
С умилением могут смотреть лисперы, запомните. А Rails-разработчики могут смотреть со смутным трепетом.
Ну хотя тут речь идет об Enterprise, а это не особо ниша рельсов, тут таки Java и прочие рулят.
Поддерживаю,

Если взять любой ORM для PHP или NET, то по сравнению с Rails проблемы следующие:

* Код компактно не получится написать

* Сложные запросы не получится написать. Все может сломаться уже на запросе вида a=b and (c=d OR c=e), не говоря о having count или order by вычисляемое поле. Приходится переходить на полностью написанный свой SQL код.

* Из своего SQL запроса, написанного без использования ORM к одной таблице, нельзя получить стандартный объект ORM. Т.е запросы
member = Member.ById(param_id)
и
member = Member.sql('SELECT * FROM member WHERE id = ?', param_id)
не будут равноценны. Второй запрос может выдать просто массив.

* Если мы создаем модель Member, то методы взаимодействия с базой данных находятся в ORM и приходится под каждый чих создавать свой метод в модели Member типа

function Member::ById(param_id)
{
connection = ORM::get_connection();
connection.get_table('member')->where('id = ?', param_id);
}
т.е. по сути получается 2 модели — одна для обычных запросов (CRUD логики), вторая для нестанартной бизнес-логики

* очень часто нужно либо хранить структуру базы в виде XML конфигов, моделей, либо при вызове ORM прописывать типы для значений, которые передаешь (характерно для NET)

Быть может, было бы неплохо начать топик с описания что такое ORM?
ORM — это такая специальная херня, благодаря которой малейшее изменение схемы базы приводит к правке кода не меньше чем в 50 местах.

Особо упоротые любители ООП каждому полю ещё прописывают геттеры и сеттеры. Чтобы жизнь тому, кто будет разгребать эту кучу говнокода, совсем уж мёдом не казалось.
Ммм, нет.

У нас например модели описана в XSD-схемах, при изменении которых DDL для таблиц СУБД и измененные Java-классы перегенерируются / рекомпилируются, так что не всегда все так плохо. Я ведь не противник ORM as such.
Прикольно! Вы только не сильно злоусердствуйте. Если весь код будет генерироваться по шаблонам, вы можете остаться без работы.
За меня не стоит так беспокоиться, написание парсеров и кодогенераторов тоже вполне интересная и сложная задача…
А миграции у вас как-то реализованы?
Какие именно? Используется www.liquibase.org/ и ручная миграция с помощью schema objects diff, через PL/SQL developer / TOAD.
ORM — это такая специальная херня, благодаря которой малейшее изменение схемы базы приводит к правке кода не меньше чем в 50 местах.
Приведите пример 50 мест, в которых приходится править код при малейших изменениях схемы данных.
И мне тоже интересно послушать. И интересно, в каком кол-ве ТЫСЯЧ местах придется править код, если ORM не использовать :)
Присоединяюсь к вопросу. С попкорном :)
наверное, вы не слышали о CodeFirst
Видимо вы не работали с современными ORM. К примеру в Entity FrameWork достаточно произвести синхронизацию с базой данный — и модель обновляется. Без правки «в 50 местах». Это к замечанию про «малейшее» изменение. Если изменение будет достаточно сильно влиять на архитектуру приложения — правка кода понадобится в любом случае.
В EF уже появились миграции?
Что именно вы подразумеваете под «миграцией»?
Допустим, мне нужно переименовать поле (колонку в БД) без потери данных. Как это сделать с помощью EF? Или, например, перенести поле в другую таблицу, без потери данных?
Вопрос поставлен не корректно.
Переименовываете колонки и переносите данные в базе — это уровень базы данных.
EF используется для того что бы вы на уровне кода могли обращаться к сгенерированной по структуре базы объектной модели.

То что вы описали — это не задача ORM.
Я пытался пояснить, почему считаю ваше замечание про EF некорректным. В настоящий момент EF не решает задач по гибкому изменению структуры БД, а может лишь уничтожать ее и создавать по новой.

Поэтому любое изменение в БД на уровне сервера БД требует тех самых изменений в «50-и местах». Иначе мы потеряем все данные в таблице, т.к. EF ее тупо пересоздаст. На сколько я слышал, функционал миграций тиснут из Ruby в EF лишь к следующему крупному релизу.

З.Ы. по поводу того, что миграции это не задача для хорошей ОРМ — можно поспорить ;-)
Стоп. ORM создает объектную модель в коде на ЯП.
«Иначе мы потеряем все данные в таблице» — каким образом мы можем потерять данные если работа с моделью базы (именно моделью базы, а не объектной моделью) происходит за пределами ORM?
ORM вообще не решает задачу «изменения структуры БД».
ORM генерирует объектную модель по существующей модели базы данных.
Не всегда, ORM-фреймворки могут еще наоборот, генерить схему БД по объектной модели. Привет, Том Кайт!
Они то может и могут. Только так лучше не делать.
Качество такой базы данных лично у меня вызывает большие сомнения. Тем более если говорим о проекте уровня Enterprise — плохо продуманная структура именно на уровне базы данных может потом вылиться в большие проблемы на остальных уровнях.
В то же время при хорошо спроектированной базе данных ORM снимает рутинную работу по маппингу объектов и записей в БД. При этом все узкие моменты можно описать хранимыми процедурами и вью. А ORM обернет их в функции и объекты. То есть опять же снимет с разработчика рутинную работу. Но при этом не стоит перекладывать на ORM те функции и задачи которые должны решаться разработчиком. Надо четко понимать для чего именно используется ORM в каждом конкретном проекте.
Я это все отлично знаю, это была тонкая ирония) как можно было заметить по привету переданному самому горячему стороннику того, чтобы плясать от базы :)
Это даже больше что бы довести мысль до логического конца :)

А Кайта мне видимо стоит наконец-то прочесть. Вы — уже не первый человек кто упоминает этого автора.
Если так, я советую начинать его читать не с книг «Оракл для профессионалов» где описывается архитектура и многие детали, а с книги «Эффективное проектирование приложений Oracle». Именно в ней даны мысли и идеи автора, подходы. А не конкретные детали.

Все имхо.
Спасибо за совет!
Это смотря что называть модным словом ORM. Это я к тому, что MS Sql это не только SQL.

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

Поэтому ORM эту задачу не решает, а фреймворк, коей частью будет ORM — может решать.
у вас опять же неверное использование ORM. Генерация ORM от объектов а не от таблиц бред. Если кто-то так делает он ССЗБ.
> Генерация ORM от объектов а не от таблиц бред.
Это почему?
Просто потому что объектная модель хуже транслируется в реляционную. Объектная модель богаче реляционной. Из простого получить сложное проще чем упростить сложное.
Если честно, не понимаю о чем именно речь. Пишу на Django, в SQL почти не лезу. Структура базы полностью создается из моделей и не требует ручного вмешательства.
ООП к примеру обладает такими свойствами как наследование, полиморфизм. Это довольно сложно реализовать в реляционной схеме. Опять же когда вы сначала делаете ER-диаграмму для приложения, а потом уже генерируете код на его базе вы получите более качественное приложение, за счет учета особенностей реляционной модели.
Объясните это Борису Нуралиеву. 1С-Предприятие 7.х и 8.х по такой схеме прекрасно работают уже второй десяток лет.
1C предприятия это, гм, не безусловный идеал…
ORM в ней работает если не идеально, то очень близко к идеалу.
Я бы сказал что это, во первых, не фреймворк как таковой, а скорее сравнительно специализированная система. А во вторых — можно поподробнее здесь? Идеал тут что? И насколько к нему близок 1С?
Идеал в том, что разработчику (не говоря уж о пользователе) совершенно не надо париться по поводу базы данных и есть ли она вообще. Работа идет с объектами приложения (справочники, документы, регистры, итд.), а система сама их проецирует в реляционную базу данных, берет на себя заботу о блокировках, контроле целостности. Даже при написании запросов используются имена объектов приложения, а не БД, и при выполнении запроса они транслируются в имена таблиц и полей БД.

Возможно, это не самый оптимальный подход в плане эффективности работы, но очень эффективный в плане скорости и простоты разработки.
Смотрите ниже. Там ORM работает вообщем-то никак. Опять же почитайте как реализованы транзакции в 8.1 поверх СУБД.
В 1С на уровне приложения есть логические транзакции, когда можно «откатить» состояние произвольного объекта. Это что-то вроде возможности выборочно откатывать уже закрытые транзакции без нарушения целостности. Не уверен, что СУБД так умеют, а сама 1С делает это неэффективно (автоматом блокирует чуть ли не всю базу целиком), но зато гарантирует целостность и непротиворечивость. В последних версиях сделали управляемые блокировки, можно даже в ногу стрельнуть, если очень надо.
В 1С на уровне приложения есть логические транзакции, когда можно «откатить» состояние произвольного объекта. Это что-то вроде возможности выборочно откатывать уже закрытые транзакции без нарушения целостности.

ORM делает через транзакции именно СУБД. А не через логические транзакции.

Не уверен, что СУБД так умеют, а сама 1С делает это неэффективно (автоматом блокирует чуть ли не всю базу целиком), но зато гарантирует целостность и непротиворечивость.

СУБД умеет лучше. Оно умеет делать это и без блокировки всей базы целиком.
Вы случайно не путаете откат всей базы до контрольной точки и откат отдельной транзакции, закоммиченной еще вчера?

Дайте ссылку или ключевые слова по поводу выборочного отката транзакций. Что-то я по «выборочный откат транзакций» или «selective transaction rollback» ничего дельного не нахожу.
Это вы транзакции в контексте СУБД и контексте бухгалтерии путаете :) Первые никакого отношения ко вторым не имеют. Первые обеспечивают целостность и непротиворечивость данных при операциях записи, вторые обеспечивают возможность отменить какие либо операции после их проведения. Разный уровень. И вот ради второго уровня блочить всю базу вместо проведения операций в отдельной транзакции достаточно бредовая идея.
Вы видели как это оно делает? К примеру обработка данных выглядит так. Делаем select * from table, далее полученные данные фильтруем уже прикладным кодом. Я бы не сказал что оно прекрасно работает. Про схему внутри базы я вообще молчу и про то что в случае файловой базы оно тупо по сетке работает очень хреново.
Это в версии 7.7, которая изначально была файловой (DBF), а потом к ней коряво прикрутили MS SQL. SELECT * она не делает, а использует курсоры. Она действительно очень хреново работает по сети, но великолепно работает через терминал, когда БД и приложение на одном компе. И не забывайте о цене решения — косарь зелени за безлимитную лицензию — это почти что даром.

Версия 8.х изначально разрабатывалась под SQL, и там маразма поменьше. Она уже вполне годно работает по сети, и позволяет писать запросы SQL руками.

А что касается самого принципа ORM «от приложения» — то он работает, и с этим трудно спорить.
Версия 8.х изначально разрабатывалась под SQL, и там маразма поменьше. Она уже вполне годно работает по сети, и позволяет писать запросы SQL руками.

Меньше, но не намного. Использование же курсоров по всей таблице мало чем от select * from отличается.
> на его базе вы получите более качественное приложение, за счет учета особенностей реляционной модели.

это зависит от бизнес-модели. чем мы рискуем — излишним качеством или недостаточной скоростью разработки?

так или иначе, изменять предметную область только из-за того, что она неэффективно хранится в БД — лютое ССЗБ. Большая часть предметных областей «реальной жизни» криво хранится в SQL-based. И эмулируя ручками переход от предметной области к SQL-based, кто поручится, что эта эмуляция будет намного лучше автоматической работы ОРМа?
Я слышал подобные подходы от тех людей, которые мутят аттрибутное программирование в БД. Ну знаете, где все аттрибуты моделей хранятся в виде имя-значение, и все чрезвычайно гибко и круто. Есть правда некоторые несущественные недостатки, например работает чертовски медленно, ибо противоречит принципам реляционной алгебры… а еще ссылочной целостности нет… и прочее.
это зависит от бизнес-модели. чем мы рискуем — излишним качеством или недостаточной скоростью разработки?

Это зависит от объема данных и предметной области. В случае если предметная область проста и понятна то сугубо фиолетово от чего генерить.

так или иначе, изменять предметную область только из-за того, что она неэффективно хранится в БД — лютое ССЗБ. Большая часть предметных областей «реальной жизни» криво хранится в SQL-based.

Эта кривизна зависит от опыта разработчика.

И эмулируя ручками переход от предметной области к SQL-based, кто поручится, что эта эмуляция будет намного лучше автоматической работы ОРМа?

Вот автомат в ORM я просто гарантирую вам наделает такое с точки зрения реляционной логики, что производительность будет ниже плинтуса. Почему? Да потому что в случае автоматической генерации базы из ORM вы можете легко не учесть необходимость третьей нормальной формы. Что приведет к значительной деградации производительности.
> Эта кривизна зависит от опыта разработчика.

эта кривизна зависит от предметной области!

вот, допустим, есть у нас документооборот. Там всё таблицами, да связями между ними. Эта задача ложится на sql.

а теперь возьмем сетевую файловую систему, или еще какие-нибудь графы и кубы. Эта задача не ложится на SQL! Документная БД — самое меньшее, что здесь нужно. Опытный разработчик может написать 2 тонны костылей, и таки заставить постгрес прохавать эту задачу, но костылями от этого они быть не перестанут.

> легко не учесть необходимость третьей нормальной формы

когда схема БД постоянно меняется в зависимости от ситуации (или разработчики кодят очень быстро, или вообще схема строится автоматически by design) — какие тут нормальные формы?!
эта кривизна зависит от предметной области!

Ерунду говорите :)

вот, допустим, есть у нас документооборот. Там всё таблицами, да связями между ними. Эта задача ложится на sql.

Особенно файлы ага :)

а теперь возьмем сетевую файловую систему, или еще какие-нибудь графы и кубы. Эта задача не ложится на SQL!

На noSQL эта задача ложится еще хуже.

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

Документная БД тут может быть нафиг не нужна. Как вы туда куб собираетесь класть или там графы?

когда схема БД постоянно меняется в зависимости от ситуации (или разработчики кодят очень быстро, или вообще схема строится автоматически by design) — какие тут нормальные формы?!

Фигню говорите. В случае если изменения идут от БД а не от кода, никаких проблем с нормальными формами не возникает. Если у вас возникают такие проблемы значит у вас проблемы с декомпозицией предметной области и реляционной логикой.
а я всегда думал что orm как раз для этого и задумывалась: проектируем entities и relations и знать не знаем ни о какой нижлежащей реляционной модели. ну это в идеале
Это работает очень плохо ;) Лучше оно работает когда у вас есть один ведущий разработчик, который обладает опытом в проектировании баз данных. Дальше он проектирует базу, делает ORM слой, пишет постановку и отдает прикладным разработчикам. Они работают со знакомой объектной моделью и слабо заморачиваются, что там дальше будет. В случае если они таки что-то делают не так, ведущий разработчик может легко найти такое место и дать канделябром по пальцам ;)
учитывая современную модель распределенной разработки, такая схема работает эээ далеко не всегда ;)
Я привел пример как это можно использовать.
Abstractions leak.
после такого вопроса ORM вам точно никакой услуги не сделает
Это был не вопрос, это было предложение к автору топика по его улучшению. Как ни крутите, но на хабре специалисты в разных областях и банально могут не знать о чем идет речь. Конечно, никто не мешает погуглить по википедии, но хорошим тоном при написании статей технических являлось бы минимальное описание того, чем занимаемся.
Хм. Предлагаете добавить ссылку на википедию в топик? да не вопрос, добавлю.
Че за чушь? Автор пишет топик как считает нужным. Если вы не знаете что такое ОРМ, тогда идете в гугл и гуглите, если вы это не удосужились сделать тогда вам это не интересно. Иначе исходя из вашего бредового! предложения, каждую статью например по django нужно начинать с рассмотрения что такое django. Поэтому откровенный чепухи не зачем советовать.
НЛО прилетело и опубликовало эту надпись здесь
SQL как правило нужен для отчетов. Нормальные ORM поддерживают управление транзакциями, чтобы у вас не возникало проблем с целостностью и при этом средства управления транзакциями могут быть декларативными, что еще сильно упрощает работу.
SQL, нужен для отчетов (сложных отчетов, по настоящему сложных), и для сложной аналитики. Разнообразные engines, которые обрабатывают массивы данных и применяя различные статистические методы и эвристики делают некоторые прогнозы, например, предсказания продаж строят. Такая логика конечно не вся живет в базе, огромная часть логики пишется в Java слое. Но написать все в Java — cлое -тоже не получается.
ORM — для OLTP-сценариев. Для аналитики (OLAP) нужно слишком много данных в слишком большом количестве видов. Для обработки большого количества данных (ETL) не катит, поскольку нужны именно данные, а не объекты и их логика, а материализация большого количества объектов потребляет ресурсы.
Эх, не вам было, а в ответ товарищу A1lfeG
Нахрена писать ручками маппинг, если уже используется ОРМ. Вот не пойму.

Пишем весь проект с использованием ОРМ. Начинаем тестировать смотрим узкие места. Если такие есть, и они узкие именно из-за ОРМ, то используем SQL через ОРМ. Если и это тормозит(что просто какой-то дикий ужас), то ищем DBA.
А вариант — «смотрим план запроса» где?
А реально ли помогал «план запроса»?
Вот трэйс помогает.

А план запроса как помогал Вам? Что с того, что он мне показал hash join?
Как узнать где тормозит по плану запроса? (знаю только, что fullscan плохо).
План запроса? Мне помогает всегда и очень сильно.

Чтобы извлекать пользу из него надо знать следующее (очень кратко и касается только оракла):

— Понимание работы Rule-based vs. Cost-Based optimizer, понимание того что такое статистика. Понимание, что FTS (full table scan) сам по себе далеко не всегда плох и иногда просто является оптимальным способом получения данных.
— Способы доступа к данным. Fullscan, index lookup, rowid-based access.
— Типа индексов (B-tree based vs bitmap индексы, когда какие лучше применять). Где и какие индексы нужны, что такое селективность индекса, что такое cardinality
— Способы доступа по индексу, что такое index unique scan, что такое range scan и что такое fast full scan, что такое покрывающий индекс, в каких случаях обращение к таблице за данными не нужно вообще, что такое index clustering factor и чем он плох…
Знание типов джойнов тоже может помочь… например sort-merge join это то, чего следует добиваться если результаты некоторой части запроса уже отсортированы

А дальше — знание что такое partitionong, partition pruning, partition-wise joins… и прочее.

Так в 10 строках сложно изложить все. Но план запроса (по крайней мере в оракле) — это бесценный инструмент.

Правда, пару недель назад в одном топике по измерению производительности мускула мне написали, что они у себя «план запроса не приводят, т.к. он и так понятно какой». Ну да, бывает :)
Тьфу, я тут кое-где напутал… например, про clustering factor следует читать «чем плохо, когда он слишком большой у индекса, и почему так происходит».
Какая разница, что ты понимаешь, что ОРМ работает неоптимально? Вариантов-то всё равно никаких. Написать свой орм разве что?
Вариант очевиден — там где он работает неоптимально, не использовать его, использовать чистый SQL и механизмы уровня СУБД. С сожалением вынужден сказать, что подавляющее большинство сервер-сайд разработчиков знает их куда хуже, чем сотни и тысячи Java-фреймворков.
Глупость откровенную говорите. Помогает он и часто. Куда поставить index, где убрать index.
и да, стоимости доверять нельзя. Она может быть большая, а запрос может выполняется быстро, и наборот может быть.
Суров, сказал — как отрезал.

«Том Кайт, Джонатан Льюис, Ричард Нимик — заткнитесь и проваливайте. Вам нельзя доверять»

Вы ведь понимаете, как работает CBO? И что такое собственно «стоимость»?

Доверять стоимости и плану безоговорочно — нельзя, да. Простой пример — если в таблице 1 запись, CBO будет скорее всего использовать full scan, независимо от того, какие есть индексы и какой запрос. Если в продакшен у вас записей 100 миллионов — все будет выглядеть совсем по другому.

Но в конкретных условиях, на конкретном железе с конкретными объемами данных — стоимость запроса — это та метрика, которая оптимизируется. Это то, что использует внутри CBO для всех своих эвристик.
Следует еще добавить, что стоимость не учитывает такие вещи, как наличие/отсутствие данных в буферном кеше (если мы говорим про оракл) и тому подобные вещи. Но это отнюдь не значит, что стоимости нельзя доверять.
Ок. вижу, что Вы прочитал Льюиса «Основы стоимостной оптимизации», и не только прочитали, но и поняли. У меня, как раз со вторым проблемы. Прочитал, а толку мало.
+1 если вы действительно ее прочитали. Я людей кто ее прочитал (или даже хотя бы листал) видел реально мало.

Еще только интересно, кому пришло в голову назвать «Основы...» (!) наверное, самую хардкорную книгу по работе оракловского оптимизатора :) Черный юмор
прочитал её всю.
А насчёт «Основ». Через всю книгу идёт мысля автора, что он полностью не уверен)
полностью не уверен в работе Оптимизатора.
ORM — для OLTP-сценариев. Для аналитики (OLAP) нужно слишком много данных в слишком большом количестве видов. Для обработки большого количества данных (ETL) не катит, поскольку нужны именно данные, а не объекты и их логика, а материализация большого количества объектов потребляет ресурсы.
Одна из основных проблем ORM это довольно немалое время которое необходимо потратить на изучение. Чем больше команда, тем дороже обучение.
Как и любая абстракция, в ней есть достаточно много мест которые нужно хорошо понимать.
Например cartesian product, N+1 selects, batches… Не говоря о фундаментальных вещах, таких 1st vs 2nd level cache, type mapping и т.д.

В одной из презентаций на InfoQ, Kevin Weil из twitter назвал ORM одним из ярких примеров leaky abstraction. Вместе с garbage collection и sql :)

ORM может помочь в определенных случаях, но нужно отчетливо понимать цену которую прийдется заплатить. А это понимание приходит только с опытом :)
Mapping view в свойства обьекта — это не ORM
Все остальное, в случае Enterprise, который в моем понимании =Oracle, делается процедурами и вьюшками

Ежели говорить про web то там совсем другие реалии. Какой-нить CMS нельзя ( точнее очень геморройно ) иметь логику в базе, потому что VCS и совместимость между движками.

Ну не только Oracle, еще DB2 и реже MS SQL.

Oracle обычно в спарке со солярисом идет, DB2 с AIX по очевидным причинам :) Подавляющая часть телекома, банков и бирж работает по таким схемам.
и тут мы плавно приходим к query builder c последующим ручным маппингом в объекты…
В качестве ORM раньше использовал LinqTOSql, Сейчас полностью перешел на использование EntityToSql.
Там где скорость работы устраивает — работаю через объекты. Если же попадается узкое место которое требует оптимизации — пишу хранимую процедуру, которая позже оборачивается ORM в функцию.
НЛО прилетело и опубликовало эту надпись здесь
Это наверно уже будет не O-Relation mapping, а O-Document и логика работы будет сильно отличаться.
По теме:
«В общем, ORM в больших проектах нужен для упрощения рутинной части. Без него — никуда :)»

Я бы сказал так — от рутины спасают соглашения. А ORM или не-ORM это — второй вопрос. Но к этому приходишь не сразу.
Соглашения спасают от рутины тогда, когда они доходят до такого уровня, что их можно абстрагировать куда -то дальше или заменить автоматизированной кодогенерацией, а иначе это такие же соглашения как java getters/setters, глаза б мои их не видели. Соглашения, но обременительны.
Ну не важно где — соглашения есть соглашения. И они тоже могут быть хорошими или плохими, не исключено. Соглашение само по себе не связано ни с кодогенерацией, ни с абстракцией, а просто некоторое поведение системы, в 80% случаев позволяющее использовать некий функционал «из коробки», без конфигурации и написания лишнего кода.
НЛО прилетело и опубликовало эту надпись здесь
Вставлю свои пять копеек.

Работал какое-то время на большом десятилетнем .Net проекте с несколькими сотнями таблиц и сложными запросами (в т.ч. отчеты всякие).

Там пользовались BlToolkit. В нем есть очень легковесный ORM, который делает только маппинг, никакого state management, lazy queries, никакой генерации запросов (хотя сейчас есть Linq-provider) и т.п. Весь sql был в хранимых процедурах, и для всех методов Data Access Layer (репозиториев) мы просто указывали имя процедуры и тип результирующего объекта.

И такой подход (после того, как я писал с NHibernate) мне очень понравился--все плюсы sql остаются (скорость запросов, полный контроль), все минусы полновесных ORM исчезают (фокусы с ленивыми запросами, производительность, необходимость изучения разных ORM + sql), и никакого ручного маппинга. Плюс нулевой порог вхождения.

Из того же разряда ORM от StackOverflow--Dapper.

Мораль: 1. надо различать легковесные и тяжеловесные ORM 2. для Enterprise проектов, по-моему, легковесные ORM--лучший выбор.
Такой же подход можно использовать и с идущими в поставке .NET (с версии 3.5) LinqToSql и EntityFramwork.
EntityFramwork кстати предпочтительнее так как имеет большое количество провайдеров для разных СУБД.
Как по мне — ваш пример, это как раз тот случай когда сохраняется баланс от удобства использования ORM и не страдает эффективность работы приложения.
Ваш проект = OLTP + OLAP

ORM позволяет сэкономить значительное время на OLTP. Всё. OLAP часть придётся всё-равно писать руками.

Личное наблюдение: многие проблемы при использовании ORM вызваны тем что «проектирование» идёт от структуры таблиц к иерархиям классов. Если делать на борот — с ORM будет меньше проблем.

Ещё один немаловажных плюс ORM в которых реализован UnitOfWork — они позволяют полностью скрыть тот факт что мы используем РСУБД. Это выражается вот в чём:
Когда вы работаете с библиотеками построенными на ActiveRecord у вас работа выглядит примерно так:

myDomainObject=myDBFramework.fetchById(id);
myDomainObject.set(....);
myDomainObject.save/update или myDBFramework.update(myDomainObject);

Так вот, с hibernate и некоторыми другими фреймворками — последний вызов не нужен, как например когда мы работаем с in-memory реализацией хранилища. Сокрытие.

Да, мне тоже всегда нравился UnitOfWork.

Но он не будет работать в веб проектах. Точнее сделать можно, но уж очень большие проблемы с этим могут быть.

Полноценно сделать UnitOfWork можно на Silverlight и с использованием WCF Ria Domain Services. Но это лишь небольшая часть веб приложений. Да и тем более это RIA.
А какие проблемы могут быть?
UnitOfWork подразумевает накопление изменений. Если это касается ORM технологии, то чаще всего это реализовано через некие сессии или контекст (EF). В рамках этой сессии необходимо существование всех объектов которые были изменены. Получается что если вы разрабатываете веб приложение (не RIA, а на подобии ServerPages), то вам необходимо хранить контекст в рамках сессии пользователя. При большом количестве пользователей это может быть накладно. Потому что для каждого пользователя необходимо хранить контекст со всеми объектами в которых были изменения.

Безусловно вы можете сказать что UnitOfWork работает в рамках каждого обращения клиента к серверу. Но, согласитесь, что это не есть полноценный UnitOfWork.
Соглашусь, но в тоже время расходы на хранение контекста и в обычных (для php) пользовательских сессиях, и в каком-нибудь EntityManager растут линейно (насколько я заметил) в обоих случаях, пускай и больше во втором в абсолютных цифрах, но, имхо, не качественно для современного железа.
Спорить не буду. Не доводилось использовать такой подход на крупных, высоконагруженных системах, потому что боялся. :) Но теперь попробую как нить. :)
>Безусловно вы можете сказать что UnitOfWork работает в рамках каждого обращения клиента к серверу. Но, согласитесь, что это не есть полноценный UnitOfWork.

Ну как раз так часто (почти всегда?) и делается. Тут просто «удачно» сошлись в одном месте идеи SOA, декларативного управления транзакциями и работа с ORM с помощью UnitOfWork.

«полноценные»/«не полноценные» — это уже больше жонглирование словами. Если граница транзакции проходит по вызову метода сервиса-«фасада» в котором осуществляется осмысленный законченый кусок работы — то имхо это и есть вполне себе unitofwork).
Да и если делать границы UnitOfWork по границам сеанса работы пользователя — то возникнет же таже проблема что и с длинными транзакциями в базе данных.
Хм, а расскажите, что у вас за энтерпрайз система такая, в которой в базу передается сформированный запрос? Многие системы (в том числе и банковские) используют принцип выноса всей бизнес логики на сторону базы данных в процедуры, легче контролировать, легче организовать безопасность. Если серверная сторона будет скомпромитированна, в любом случае никакие конкретные запросы, кроме того что выдают процедуры, выполнить не удастся. А какое у вас направление системы?
Согласен что многие системы используют принцип выноса бизнес логики. Но не согласен что чаще используются хранимки. Чаще сервер приложений, все таки.
Если вы не представляете себе жизни без ORM, то, скорее всего, вам ни ORM, ни RDBMS не нужно вообще.
Используйте объектные базы данных (ODBMS), например Caché
Не используйте Cache! Никогда! Уж извините.

Вам всегда будут говорить что Cache это самая быстрая БД на свете*. И вы знаете, это не ложь.

*При прямом доступе через глобаллы. Когда, когда вы, по сути, работаете напрямую с памятью.
И Cache не объектная БД. А постреляционная.
Бл#ть! Я аж кипю весь! Как можно было человеку посоветовать использовать Cache?

Cache не создает проблем, только тогда, когда эта гадость используется только как СУБД. Но это означает что вы будете использовать SQL уровень работы с этой хреновиной. И никаких «объектных» вещей на этом уровне вы не увидите. И не дай бог вам залезть глубже…
Объясните, чем он так плох :)
1. Это не объектная СУБД, а постреляционная. Это означает, что когда вы планируете создать класс и наследник от него, то это означает что создастся (вот тут буду говорить грубо, потому что проще будет понять, хотя надо бы говорить на уровне глобаллов) две таблицы со связью 1-1. Т.е. таблица родитель и таблица наследник. Никогда не пробовали реализовать наследование в реляционной модели?
2. Вы работали с Cache-Script и пробовали писать на этом? Вы будете шокированны. До сих пор помню момент, когда передавал в метод сразу свойства объекта (типа obj.Property), и данные не приходили. Знаете почему? Я тоже нет. Но стоили создать переменную, положить в нее значение и саму переменную передать, то все было ок. Не пытайтесь найти сейчас причину. Мы бились над этим дня три, и не поняли ничего. Это было именно в конкретно месте. Там был условный оператор, в котором вызывался метод. Типа if(SomeMethod(obj.Property))…
3. Как вам IDE?
4. Скорость работы не через глобаллы.
5. Глобаллы. Это такая херь с которой можно работать. Это деревья. При работе напрямую с глобаллами вы можете сделать операции ОЧЕНЬ быстро. Но при этом вы теряете проверку целостности данных. Т.е. вы можете записать в глобаллы абсолютно любые данные, и каше не ругнется. Потому что она позволяет вам сделать все что угодно.

Можно вспомнить и найти еще разные штуки, но я думаю этого уже хватает. :)
Ай. Я делаю всегда очень просто.

1. Выясняю детали проекта. Если необходимо будет менять структуру БД «на лету», то тогда ORM не использую. Либо, выясняю есть ли возможность использовать метаданные.
2. Во всех остальных случаях я использую ORM.
3. Если возникают проблемы с производительностью или невозможностью на основе ORM построить грамотный запрос, то перестаю в этом месте использовать ORM.

Всегда я начинаю использовать ORM по дефолту. И никогда не парился. И думать тут нечего. Плюсов от ORM столько, что глупо от них отказываться из за возможных проблем. Даже если проблемы появятся, то никто не мешает вам в конкретном месте перестать использовать ORM.
Я вижу тут много консерваторов: хранителей сакральных знаний чистого SQL, создания сайтов на С и Ассемблере.
Скажу из личного опыта, что хотя я и не в гуру в SQL, но многие знания в создании сложных запросов я получил именно анализируя SQL, созданный ORM. До этого я знал SQL на уровне простых запросов, связей и основ проектирования БД. И уже потом после чтения кода, генерируемого ORM, когда я читал книги по чистому SQL — они мне давались очень легко.
Спор использовать ORM бессмысленен. Гвозди можно забивать и молотком и кувалдой, оба инструмента предназначены для забивания. Но ни один вменяемый человек не будет забивать маленькие мебельные гвозди кувалдой. В то же время большие колья забивать молотком глупо и не эффективно.

Пока у вас в процессе разработки идут гвозди — пользуйтесь молотком, когда пойдут колья — не забудьте взять в руки кувалду.
Извините, но что вы подразумеваете под кувалдой, а что под молотком? :)
:) А вы молодец. :)

Но вы использовали абстракции по отношению к прямому SQL доступу и ORM. Что для вас кувалда и что молоток, если продолжать аналогию? :)
На самом деле сложно провести прямую аналогию, так как выполняемые работы сильно отличаются.

С одной строны молоток — это чистый SQL, так как позволяет выполнять более тонкую работу, в то время как кувалда штука тяжёлая и неповоротливая.

Однако с другой стороны, кувалда тоже может быть SQL-ом, так как позволяет намного эффективнее решать именно тяжёлые задачи, а мелочами пусть молоток занимается.

Вобщем, однозначного ответа на ваш вопрос нет. К сожалению.
Вот и я про тоже. С одной стороны вы сказали очевидные вещи, но потом вдумаешься… И как то непонятно становится.

А так да, все верно. :) Подписываюсь под вашими словами.
В карму вам плюнул. :) Уж очень мне понравилось. :)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории