ActiveRecord - зло?

гемоглобин

Новичок
Правильно ли я понимаю, что ActiveRecord - это своего рода антипаттерн, потому что объекты бизнес-логики сильно завязаны на конкретом способе их хранения? Или это всё бред и неважно?
 
  • Like
Реакции: AmdY

MiksIr

miksir@home:~$
Я, если чесно, не понял, что значит "объекты бизнес-логики", но рискну предположить, что нет, не правильно понимаете.
 

гемоглобин

Новичок
Я, если чесно, не понял, что значит "объекты бизнес-логики".
Ну, например, "пользователь", "корзина". А элементы бизнес-логики например такие: "пользователь положил товар в корзину". Это еще называется доменом.

но рискну предположить, что нет, не правильно понимаете.
?
 

Adelf

Administrator
Команда форума
Ну, например, "пользователь", "корзина". А элементы бизнес-логики например такие: "пользователь положил товар в корзину". Это еще называется доменом.
Вот на этом конкретном примере покажи - что в AR плохо и почему.
 

Духовность™

Продвинутый новичок
Да. Но отнюдь не потому, что "завязаны на конкретном способе их хранения", а потому, что мешается 2 совершенно разных слоя - слой бизнес-логики и слой, который эту логику записывает в СУБД.

У меня вот есть 2 типа классов в системе, которые являются моделью - это сущность, т.е. грубо говоря объект чего-то (Пользователь, статья) и их мепперы - классы, которые создают/сохраняют/удаляют эти объекты сущностей, т.е. гоняют их из базы в программу и и обратно. Изначально всё было независимо и классы моделей вообще ничего не знали о мепперах.

Но когда возникла потребность делать ленивую загрузку
PHP:
$article->getTags()
, т.е. заполнять объект Article какими-то данными, из соседней таблицы (а данном случае - tags) то возникла дилемма - как это сделать?
Вариант 1 был таков:
PHP:
$article_mapper->fillArticleTags($article);
- тут данный метод fillArticleTags вытаскивал данные из СУБД, из таблицы tags и заполнял ими объект Article.

Но этот вариант был какой-то убогий во всех планах. Например, нельзя было в шаблоне сделать Lazy Load, приходилось заполнять объект статьи заранее, в контроллере. Это бесило.

В результате была реализована схема, согласно которой каждый объект сущности, т.е. каждый объект бизнес-логики содержал в себе ссылку на репозиторий всех возможных мепперов системы. Соответственно, появились такого рода коды ленивой загрузки:

PHP:
// На примере объекта "Административная группа"
class Group ...
    /**
     * Возвращает коллецию объектов доступа.
     *
     * @param void
     * @return Cover_Array
     */
    public function getAccesses()
    {
        if ($this->accesses === null)
        {
            foreach ($this->mapperManager
                          ->getMapper('Group/Access')
                          ->findListByGroupId($this->getId()) as $access)
            {
                $this->setAccess($access);
            }
        }

        return $this->accesses;
    }
т.е. с одной стороны идёт явное отделение бизнес-логики от способа хранения, с другой - мы не ограничиваем жестко модель в её способности быть совмещенной с БД.
 

гемоглобин

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

Духовность™

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

Если так интересно, то:

Для исключительных случаев: получаю данные и руками формирую нужные объекты. Это в ситуациях, когда я не хочу "для каждого пользователя по отдельному запросу на каждую связь с другой таблицей". Пример такого говнокода: http://pastebin.com/nAsWXQ5Z

Как я буду делать: как ты сказал. В контексте моего примера с группами:

PHP:
foreach ($groups as $group) {
    $group->getAccesses(); // таки да - тут выборка для каждой группы. 
}
Но фишка в том, что у меня своя реализация и своё видение ORM, свои плюсы и в одном сообщении все не расскажешь.
 

AmdY

Пью пиво
Команда форума
гемоглобин
да, любой паттерн становится антипаттерном, когда он начинает применяться не к месту.
но в то же время паттерны получаются максимально эффективными, если готовятся из нескольких ингредиентов и смешиваются в нужной пропорции. тот же мэппер повесить вполне логичный тюнинг, даже, необходимый. да ещё DBAL напрашивается. но только в рамках разумной абстракции, если способ хранения не планируется менять, то зачем заморачиваться?

Духовность™
гы, я как раз писал развёрнутый ответ.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Как написал недавно умный человек по нику StUV, ко мнению которого я прислушиваюсь, мапперы мы используем в любом случае, аргументов против datamapping-а уже не осталось.
AR очень хорош в большинстве CRUD-операций. Особенно - вместе с генератором кода, который сам по внешним ключам таблиц прописывает в классах моделей связи, правила валидации данных по типу и размерности, соответствие столбцов и названий.
Время разработки простейших операций сокращается раз в 20, скорость исполнения падает на проценты.

Есть 2 ситуации, где AR плох - very high load, которого у вас не будет, или Вы сами все знаете, и сложные запросы, которые гораздо лучше заворачивать в отдельные методы.
 

AmdY

Пью пиво
Команда форума
из-за отсутсвия мэппера в очередной раз придётся отложить публичное выкладывание своего фреймворка, в текущем проекте вылезли некоторые неприятные проблемы. хотя я предпочитаю Table Data Gateway
(поправил название паттерна)
 
Сверху