Какие запросы мешают вам использовать ORM?

bkonst

.. хочется странного?...
Какие запросы мешают вам использовать ORM?

После проведения раскопок среди публично-доступных ORM-библиотек из списка на PHP Wiki создалось впечатление, что все они позволяют использовать только самые примитивные условия выборки (вида "равно/не равно", "больше/меньше"), а при необходимости связывания таблиц единственной альтернативой является использование "сырого" SQL или какого-нибудь SQL-подобного языка.

Почитал обсуждения ORM / паттерна QueryObject (например Конструктор SQL-запросов и Постоение SQL запроссов. Active Record. Реализация. Паттерны.). Похоже, что у опытных программистов на почве урезанных возможностей ORM-библиотек сформировалось стойкое отвращение к автоматической генерации SQL.

Возник вопрос: насколько востребована была бы ORM, позволяющая строить сложные критерии отбора по связанным таблицам (допустим, построение запроса, упомянутого в http://phpclub.ru/talk/showthread.php?s=&postid=651520, могло бы(*) выглядеть так:
PHP:
$filter_gsm = new ORMFilterReferring("Phone", "Property", new ORMFilterEquality('val', '2'));
$filter_vib = new ORMFilterReferring("Phone", "Property", new ORMFilterEquality('val', '10'));

$filter_subproperties = new ORMFilterCompositeAND();
$filter_subproperties->add_filter($filter_gsm);
$filter_subproperties->add_filter($filter_vib);

$phones = $manager->items($filter);
), с использованием аггрегатных функций и предиката EXISTS? По моему, такой инструмент позволил бы обойтись без написания SQL вообще(**), что улучшило бы переносимость и значительно сократило бы объем рутинных работ. Есть ли, с вашей точки зрения, в этом какие-то неочевидные подводные камни? Встречали ли вы какие-нибудь (достаточно часто используемые) виды запросов, которые не уложатся в подобную схему?

(*) все совпадения с реально существующим кодом случайны ;)
(**) поймите меня правильно, я ничего не имею против SQL; мне не нравится рутинное написание огромного количества почти одинаковых запросов.
 

mrjazz

Новичок
Суть не столько в автоматическом построении сложного запроса а в абстрагировании объектов модели от самого хранилища данных. В этом контексте мне очень нравится cakephp, со своим подобием ORM. При этом оставляя возможность для "хаков" SQL'ем. Т.е. мое ИМХО: автоматизация ради упрощения и только там где надо, а не автоматизация ради автоматизации, усложняя в разы реализацию.
 

whirlwind

TDD infected, paranoid
Почти у всех ORM-ов есть одна принципиальная проблема, которая сводит на нет всю прелесть ORM. Товарищи использующие ORM-ы пытаются требовать невозможного - удовлетворительного выполнения всех мыслимых и немыслимых запросов, какие только можно придумать.

Забудьте про это! Не будет ORM Одинаково хорошо работать например в разных по смыслу контроллерах, потому что конечное применение модели сильно зависит от контекста. Из всех языков я знаю только Perl - он распознает два контекста в зависимости от синтаксиса написания. Здесь ситуация на порядки сложнее.

Базовые возможности, реализованные как CrUD для базового класса + режим итератора и основные фильтры позволяют реализовывать практически любые алгоритмы без огладки на производительность.

Следующим уровнем может быть кеширование, но не нужно думать что UofW - это панацея. Во первых - не везде она нужна, т.к. ORM может и должен нормально работать не только в WEB-приложениях, но и в оффлайновых долгоиграющих, когда между двумя операциями одной программы, модель может быть модифицированна другой программой.

Написания SQL-конструкторов ну это в самом деле - проще руками написать запрос. Так что это совсем даже не выход.

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

PHP:
$status = new OrderStatus();
$status->filterBy("cid",Array("auth","decl"));
...
$ld = new BulkLoader();
$ld->attachEssence(new Order);
$ld->attachEssence($status);
$ld->attachEssence(new OrderLine);
$ld->attachEssence(new Product);
$ld->fetch();
...
Понятно, что первая сущность - опорная. Т.к. на OrderStatus есть референс из Order, а сам по себе статус не ссылается ни на что, то это джойн с таблицей ордера. Обратная ссылка OrderLine на Order это группировка по полям ордера. Ссылка на продукт у нас в OrderLine -> джойн OrderLine + Product.

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

zerkms

TDD infected
Команда форума
whirlwind
на днях дважды реализовывал отношения в нашем проектике... дважды удалял...
второй вариант пал как раз изза группировок.... следующие опыты показали: что достаточно сделать подключение related (хз как по-русски сказать это же;) ) объектов только для одного уровня... и если отношений 1:n будет не больше чем 1, тогда извлечь данные и растасовать по объектам никакой сложности нет...
если 1:n 2 и более, тогда иного решения, кроме как lazy loading я не вижу...

bkonst
твои примеры с критериями - отнюдь не новинка, тот же propel весьма и весьма удачно разруливает запросы с критериями через объекты одноимённого класса - criteria
 

atv

Новичок
По моему, такой инструмент позволил бы обойтись без написания SQL вообще(**), что улучшило бы переносимость и значительно сократило бы объем рутинных работ.
Скажи, тебе удобно общаться на русском языке, или для тебя это рутинная работа? Попробуй всё то, что ты написал на русском языке, переложить на PHP.

SQL язык разрабатывался в своё время специально для непосредственного применения людьми, работающими на компьютере. Именно поэтому запросы выглядят как полноценные выражения на английском языке.

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

Как по мне, ORM это мёртворождённый ребёнок.
 

zerkms

TDD infected
Команда форума
atv
хехе, уж где-где, а в IT сфере панацеи нет и не будет. критично высказываться что хорошо, а что - нет мягко говоря опрометчиво.
И про ОРМ в том числе. Хороший инструмент, позволяющий уменьшить число запросов, которые пишутся программистом, как говорится, "ручками" - означает ускорение разработки и уменьшение ошибок.
Вы за реюзабельный код?
Я - за. Если так - то зачем каждый раз учить свой класс уметь записывать свои изменения в БД? Зачем? Разве не проще сделать $ar->save(); и быть увереным, что запрос уже написан и отлажен?
А запросы на получение данных? То же самое...
Так что позволю заметить что вы всё таки не совсем правы ;)
 

bkonst

.. хочется странного?...
mrjazz
Суть не столько в автоматическом построении сложного запроса а в абстрагировании объектов модели от самого хранилища данных.
Ну, для этого достаточно и стандартного набора CRUD. Однако в тот момент, когда захочется чего-нибудь странного (a-la "выбрать всех клиентов, общая сумма покупок которых в категориях товаров, содержащих более чем X наименований, составляет больше N рублей"), мы опять возвращаемся к SQL, специфике хранилища данных и прочим прелестям, которых хотим избежать. Вопрос как раз в том, насколько страшна для вас смесь ORM и SQL-"хаков" (давайте забудем о "сложности реализации" самой ORM; в конце концов, мы же не говорим сейчас о сложности реализации СУБД - она просто уже есть. Будем считать, что достаточно мощная ORM тоже "уже есть").

whirlwind
Почти у всех ORM-ов есть одна принципиальная проблема, которая сводит на нет всю прелесть ORM. Товарищи использующие ORM-ы пытаются требовать невозможного - удовлетворительного выполнения всех мыслимых и немыслимых запросов, какие только можно придумать.
От SQL требуют примерно того же, и это не считают "проблемой". Мое личное мнение (которое я сейчас пытаюсь проверить): необходимость лезть на более низкие уровни абстракции (то есть писать SQL-хаки при использовании ORM) - это ситуация нештатная. Точно так же, как и желание "сделать цикл в SQL". Другое дело, что те ORM, что сейчас доступны, не дают достаточно возможностей для этого(*).

Следующим уровнем может быть кеширование, но не нужно думать что UofW - это панацея
Немного отклонюсь от темы и спрошу, как расшифровывается "UofW"? Сходу ничего подходящего по это сокращение не вспоминается.

Написания SQL-конструкторов ну это в самом деле - проще руками написать запрос. Так что это совсем даже не выход.[...]
Для того, что бы строить хорошие быстрые запросы без набивания SQL-кода, нужен объект, анализирующий связи до и группирующий результат после.
Примерно про это я и говорю. Работа со связями - это слабое место существующих ORM(**). Так вот, если бы они могли анализировать связи и обеспечивали автоматическую загрузку (или загрузку по требованию) связанных объектов и/или - с вашей точки зрения, насколько бы сильно это повлияло на процесс разработки/сопровождения? Естественно, стоимость разработки самого "конструктора"/"анализатора" в расчет не берем.

zerkms
вои примеры с критериями - отнюдь не новинка, тот же propel весьма и весьма удачно разруливает запросы с критериями через объекты одноимённого класса - criteria
Он при этом может учитывать связи между сущностями? Я поднял тему именно из-за того, что практически все ORM, что я видел, в этом месте прихрамывают.

Например, вот что я смог найти (оригинал здесь)
PHP:
$c = new Criteria();
$c->addJoin (OrderPeer::STATUS, StatusPeer::NAME);
$c->add(StatusPeer.ORDER_TYPE, 'purchase');
$orders = StatusPeer::doSelect($c);
Не самый лучший вариант, так как в нашей (всей из себя объектной) модели внезапно появляется искуственный 'join'. Опять-таки, непонятно, как себя повел бы propel в том случае, если бы потребовалось использовать несколько связей с зависимыми объектами одного типа (при формировании запроса, похожего на тот, что я упомянул в начале нити).

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

Точно так же, ORM - это дополнительный уровень абстракции, который позволяет не писать SQL запросы, отличающиеся только именами таблиц. Я не могу сказать на SQL, что-де "этот шаблон запроса следует использовать для сохранения класса"; SQL часто приходится создавать динамически в зависимости от данных, передаваемых пользователем. И вот, в тот момент, когда реализуется набор Create/Retrieve/Update/Delete - мы уже приходим к примитивненькому ORM и говорим "А". Остается только сказать "Б" и заставить ORM выполнять достаточно функций, чтобы отпала нужда в использовании SQL (мы ведь не хотим сразу работать на куче уровней абстракции, правда?).

(*) опять-таки, моё личное мнение
(**) либо оно очень хорошо спрятано в документации
 

zerkms

TDD infected
Команда форума
Немного отклонюсь от темы и спрошу, как расшифровывается "UofW"? Сходу ничего подходящего по это сокращение не вспоминается.
Unit of Work

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

в моём "наколенном" простом орм при добавлении критерия юзается имя присоединяемой сущности типа
$criteria->add('statusPeer.field', 'purchase');
 

atv

Новичок
Вы за реюзабельный код? Я - за. Если так - то зачем каждый раз учить свой класс уметь записывать свои изменения в БД?
Точно так же, ORM - это дополнительный уровень абстракции, который позволяет не писать SQL запросы, отличающиеся только именами таблиц.
Я к тому и говорю, что считаю ORM неудачной абстракцией, потому и проблем с ней много.

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

Мне больше по душе DataSet'ы. Любой срез данных представляет собой таблицу, вот и работай сней, и никаких сюрпризов.
 

whirlwind

TDD infected, paranoid
>Так вот, если бы они могли анализировать связи и обеспечивали автоматическую загрузку (или загрузку по требованию) связанных объектов и/или - с вашей точки зрения, насколько бы сильно это повлияло на процесс разработки/сопровождения?

В моем варианте ORM это есть. Это работает круто, но мы с zerkms говорим уже о другом.

Если поюзать систему с загрузкой первого related уровня, то можно выявить что не всегда это нужно. Например ситуация с заказом, где есть ссылка на кастомера, адверта, статус ордера. Для вывода некоторых списков не обязательно нужны все эти ссылочные данные. Если реализовывать BulkLoad прозрачно на уровне ORM, то возникнут ситуации, когда выполняется лишняя работа. По этому моменты использования BulkLoad ИМХО полностью на совести программиста. В типичных случаях используется базовый запрос по одной таблице, а подгрузка объектов выполняется в момент ->get().

-~{}~ 23.09.06 21:33:

>a-la "выбрать всех клиентов, общая сумма покупок которых в категориях товаров, содержащих более чем X наименований, составляет больше N рублей"

>мы опять возвращаемся к SQL, специфике хранилища данных и прочим прелестям

А это не имееет никакого отношения к ORM. При кривой структуре базы это будет непросто сделать и в виде одного запроса.

Просто эт тоже отдельная категория запросов, где общее колво обрабатываемых элементов изначально неопределено, это во-первых. Во вторых, если у вас активная модель, ничто не мешает вам сделать это в три строки используя бизнес-логику ваших устойчивых классов. Если у вас это плохо получается - значит пока заняться рефакторингом/редизайном. Но опять таки, ORM не виноват в кривых руках. Используя ORM вы пытаетесь решать задачи, а не доказать что это плохая технология и завалить эту технологию убийственными запросами. Все просто - либо вы используете ORM, либо нет.
 

whirlwind

TDD infected, paranoid
А что тут обосновывать? Если вы используете ORM, вы все делаете так, что бы облегчить решение задач с помощью ORM, но это !== переложить всю работу на ORM. Вы больше думаете о дизайне и меньше пишете. Вот это ORM.
 

WP

^_^
Imho, ORM это бред. Можно написать некий абстрактный класс добавления условий, например при запросе поиска по сложным условиям, когда юзер заполняет большую форму с динамическими полями, возможно использование класса оправдано, и то можно написать без этого. А вот генерировать статические запросы вселенский изврат. Во-первых это идеологически неверно, т.к. SQL не требует диалектов, для этого и создан. Ведь сами подумайте - бред, сначала создавать запрос, а потом его же парсить (СУБД). Во-вторых это требует ресурсов, куда больше чем прога без извратов там где в запрос подставляется все простой конкатенацией, и можно обойтись тернарным оператором в большинстве случаев.

-~{}~ 24.09.06 00:16:

whirlwind
Угу, для ламаков это.
Дизайн это когда все летает и программер понимает. Дизайн != избыточная абстракция.
 

whirlwind

TDD infected, paranoid
WP точно, бред, если рассматривать его с точки зрения _механизма_построения_запросов_. Но, ORM - это не механизм построения запросов, если ты не в курсе. Держу пари, ты не используешь ООП или используешь его ограничено.

-~{}~ 24.09.06 00:29:

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

WP

^_^
whirlwind
Это когда задаешь модель запроса, а он тебе его строит сам из объекта. Это механизм, так сказать, подготовки запроса. Да, я ограничено использую ООП, т.к. он нужен только там где он нужен, а если писать все на нем, будет жутко лагать и некрасиво. Я знаю что можно привести множество аргументов и т.д., я их и сам могу привести, но мне так намного удобнее чем создавать множество объектов и их вязать. Какие-то сущности библеотечные выношу в класс (и создаю объект от него), они классы редко изменяются в процессе разработки, скорее появляются новые.
Веб-проектов у меня вовсе не так много, т.к. этим я не зарабатываю на жизнь, другое призвание (тоже в IT). Причем тут требования, и частота их изменения? Кухарка никогда не будет перепроектировать БД. А программер может и без всякой ерунды типа ORM.
А на что тут обижаться? :) На них воду возют.

-~{}~ 24.09.06 00:45:

п.с. такой же абсурдец как пытаться формализовать проверку форм. Вроде бы будет работать, но хреново.
похоже ты пытаешься доказать, что велосипед гораздо круче фуры: он не так воняет, да и поставить его можно в коридоре. Ты конечно прав, но только для тех, кому не нужно возить двадцатитонные контейнеры.
Отредактировано whirlwind 24.09.06 в 00:39
Велосипедом является как раз ORM, ведь оно оправдано лишь в некоторых случаях, когда речь идет об однотипной выборке по куче статических критериев без связи. Например юзерской инфы (анкеты). А на фуре можно хоть слонов хоть мышей возить.
 

Frol

Новичок
Да, я ограничено использую ООП, т.к. он нужен только там где он нужен, а если писать все на нем, будет жутко лагать и некрасиво. Я знаю что можно привести множество аргументов и т.д., я их и сам могу привести, но мне так намного удобнее чем создавать множество объектов и их вязать. Какие-то сущности библеотечные выношу в класс (и создаю объект от него), они классы редко изменяются в процессе разработки, скорее появляются новые.
и с чего ты это вдруг стал утверждать, что ORM бред?
 

whirlwind

TDD infected, paranoid
WP Ну ладно, раз уж сеня суббота, давай пофлеймим немного. Вот ты говоришь

>Какие-то сущности библеотечные выношу в класс

Конечно, ООП можно использовать для группировки некоторого набора функций, но почти то же самое что забивать гвозди микроскопом.

И еще такой вопрос: можно сказать что ООП это следующая ступенька программирования? Т.е. означает ли что программер, который может мыслить ООП, автоматически может писать в процедурном стиле? Я думаю да. А обратное, когда работая в модульном стиле так же легко можно работаеть в ООП так же верно? Не думаю. Так о чем тогда спор, если ORM - это отражение классов на БД? Т.е. если ты ООП не используешь, как ты можешь судить плохо юзать ORM или хорошо?
 

WP

^_^
В общем это выбор каждого знающего оба подхода. Именно ВЫБОР. Я его сделал.
 

master_x

Pitavale XXI wieku
WP
В общем это выбор каждого знающего оба подхода. Именно ВЫБОР. Я его сделал.
плохая отписка. я бы тебе посоветовал такой выбор: не писать в тему если не знаешь о чем пишешь.

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

zerkms

TDD infected
Команда форума
кстати - в теме очень много разговоров ведётся о т.н. "сложных" запросах, которые якобы не сможет разрулить ОРМ.
а можно хотя бы примерное соотношение не сложные/сложные запросы в ваших среднестатистических проектах и собственно 1-2 примера этих самых запросов?
 
Сверху