Comments 81
Жесткую привязку к 'id' надо заменить primary key
+2
Еще вопрос будет ли оно корректно работать с relations child->parent и не лезть в базу за одним и тем же parent для 10 child?
+2
В базу оно будет лезть точно так же как и раньше, преимущество приведенного метода только в том, что не будет путаницы с одинаковыми объектами разнесенными по всем скриптам. Т.е. оно будет лезть 10 раз, но объект parent будет создан только один.
Чтобы не лезло в базу нужно перехватывать момент «перед запросом», но без создания новой прослойки между моделью и CActiveRecord так, увы, сделать не получится.
Чтобы не лезло в базу нужно перехватывать момент «перед запросом», но без создания новой прослойки между моделью и CActiveRecord так, увы, сделать не получится.
0
Все уже украдено до вас github.com/phpnode/YiiBlocks/tree/master/identitymap и грамотней, раз тоже лезет в базу, то никаких преимуществ…
+5
Метод по ссылке предполагает наследоваться от AActiveRecord, а это, согласитесь, как-то странновато…
Хотя это, пожалуй, недоработка фрэймворка, что нельзя по другому решить проблему.
Хотя это, пожалуй, недоработка фрэймворка, что нельзя по другому решить проблему.
0
Ну у меня модели итак наследуются от моей модели, что мешает мне мою модель унаследовать от AActiveRecord вместо СActiveRecord?
+1
длинная цепочка наследования — это не есть хорошо.
0
Тесты и только тесты ;)
+1
Опять же они и наследуются, чтоб не городить ваш код protected function instantiate в каждой модели
+2
Опять же, в данном случае это недоработка фрэймворка.
И вот такое ConcreteModel < — AActiveRecord < — BActiveRecord < — CActiveRecord отнюдь не признак хорошей архитектуры =)
И вот такое ConcreteModel < — AActiveRecord < — BActiveRecord < — CActiveRecord отнюдь не признак хорошей архитектуры =)
+3
А я думал это просто механизм ООП…
0
Как сделать лучше?
+1
Что именно? Если Вы про такую структуру классов, то искать решения без наследования. С помощью тех же events. Но, как я писал ниже, нельзя перехватить событие перед отправкой запроса. Во время CActiveRecord::beforeFind() модель и все остальное пусто и нет возможности узнать по какому Id запросили модель(я по крайней мере не нашел).
0
getRecord принимает строку, а addRecord — объект. Послелний вариант, имхо, лучше.
Зачем нужно инстанцирование у ObjectWatcher, не лучше ли ограничиться статическими методами?
Зачем нужно инстанцирование у ObjectWatcher, не лучше ли ограничиться статическими методами?
0
на вид обычный Singleton
+1
Странно то, что Active Record в Yii не включает в себя Identity Map.
0
Попробуйте им доказать, что оно им надо, очень удивитесь, мне хватило просьбы отключить double encode в htmlspecialchars…
0
Как раз одна из причин по которым все таки свой фреймворк бывает предпочтительнее в некоторых случаях. Благо есть время им заниматься.
0
Отключение double encode действительно штука очень сомнительная потому как поощряет делать лишний раз encode. Так можно и до отключения notice во view дойти.
0
С ним есть определённые проблемы. См., например, ниже про Rails.
0
1. Зачем два раза выбирать одну и ту же модель?
2. Какой смысл в indentity map, если всё-равно делается запрос к базе, даже если модель уже имеется.
2. Какой смысл в indentity map, если всё-равно делается запрос к базе, даже если модель уже имеется.
+4
1. child->parent
2. какой смысл делать запрос в базу, если его результат в виде объекта уже есть?
2. какой смысл делать запрос в базу, если его результат в виде объекта уже есть?
0
1. М?
2. Например, для того, чтобы убедится, что результат более-менее актуален. Или для того, чтобы получить чистый объект, а не тот, с которым мы, ещё не сохранив, поработали.
2. Например, для того, чтобы убедится, что результат более-менее актуален. Или для того, чтобы получить чистый объект, а не тот, с которым мы, ещё не сохранив, поработали.
0
1. в одном месте вытянули модель через отношение, в другом месте обратно. Да разве не может быть случая, когда в рамках запроса требуется дважды работать с объектом в разных контекстах?
2. То что делается запрос — это недостаток, но его нельзя решить нормальным методом силами фреймворка, т.к. нет возможности перехватить момент «перед запросом».
2. То что делается запрос — это недостаток, но его нельзя решить нормальным методом силами фреймворка, т.к. нет возможности перехватить момент «перед запросом».
0
1. Может. Если это всё read, то проблемы нет. Если не только read, может стать сложно и плохо.
2. beforeFind выполняется перед запросом и в нём доступен критерий запроса.
2. beforeFind выполняется перед запросом и в нём доступен критерий запроса.
0
$this->getDbCriteria()? Если да, то в нем:
CDbCriteria#1
(
[select] => '*'
[distinct] => false
[condition] => ''
[params] => array()
[limit] => -1
[offset] => -1
[order] => ''
[group] => ''
[join] => ''
[having] => ''
[with] => null
[alias] => null
[together] => null
[index] => null
[scopes] => null
[CComponent:_e] => null
[CComponent:_m] => null
)
0
www.yiiframework.com/doc/api/1.1/CActiveRecord#beforeFind-detail там ниже написано под методом что вам нужно
0
А как обратиться к этому «скрытому» параметру? =)
0
Я думаю только подписавшись напрямую на событие onBeforeFind, затем уже его обрабатывать и брать из него criteria как $event->criteria; иначе вы просто перекрываете реализацию CActiveRecord beforFind();
0
А можно небольшой ошмёток кода для вопроизведения?
0
в модели
Вызываю через findByPk как указано в топике.
protected function beforeFind() {
CVarDumper::dump($this->getDbCriteria(),10,true);
}
Вызываю через findByPk как указано в топике.
0
SamDark, кстати, так надо или это баг, т.к. $criteria всегда будет null, т.к. ничего функции не передано, м? www.yiiframework.com/doc/api/1.1/CActiveRecord#beforeFind-detail Т.е. возможно в query нужно передавать в beforeFind() еще и $criteria? www.yiiframework.com/doc/api/1.1/CActiveRecord#query-detail
0
Да я все о том же, о наболевшем, что мои несчастные 10 child дергают из базы 10 однояйцевых parent, не более…
+1
Умгу. Да, это нормальный, в общем, пример. Тут действительно пригодилось бы.
0
А разве кеширование не может решить ту проблему о которой пишет Dr_Death?
Ведь по большому счету эта проблема проектирования.
Ведь по большому счету эта проблема проектирования.
0
Может.
0
Т.е. даже Identity Map нету, потому что вдруг нужен актуальный объект и прочее, а мне предлагают объекты загнать наглухо в кэш. Помниться как то просил кэшить child->parent только на время выполнения скрипта, чтоб на одной странице много раз не вызывался и юзал результаты первого запроса, так и то столько про актуальность чего то там наговорили, а тут фигачить все в кэш и не жаловаться…
0
Тут смотря какая задача. При выборках обычно актуальность не так важна, как при изменении данных.
Я тут подумал, случай с parent-child тоже не сильно однозначный. Если нужно построить дерево, выбирать лучше всё и сразу. В остальных случаях, скорее всего, можно обойтись без identity map и дополнительной выборки, если поменять исходную точку запроса. Если более конкретный пример дадите, можно будет попробовать решить красиво без identity map.
Я тут подумал, случай с parent-child тоже не сильно однозначный. Если нужно построить дерево, выбирать лучше всё и сразу. В остальных случаях, скорее всего, можно обойтись без identity map и дополнительной выборки, если поменять исходную точку запроса. Если более конкретный пример дадите, можно будет попробовать решить красиво без identity map.
0
Т.е. 10 parent которые по сути один и тот же, но на самом деле 10 разных, можно изменять по разному в разных местах и при этом говорить о какой то актуальности измененных данных?
Мне пока lazy load нравиться больше, чем лазить каждый раз и дописывать join и прочее with вместо child->parent->parent
Мне пока lazy load нравиться больше, чем лазить каждый раз и дописывать join и прочее with вместо child->parent->parent
0
Зависит от конкретного примера. Может у вас вообще read-only дерево. Тогда можно что угодно делать и как угодно.
Lazy load так и так будет менее эффективен, чем eager. Даже с identity map. Это, конечно, если не кешировать.
Lazy load так и так будет менее эффективен, чем eager. Даже с identity map. Это, конечно, если не кешировать.
0
Как раз таки непонятно что надо делать с parent чтоб он был нужен в разных местах, еще и с разными данными внутри еще и не сохраненными, без абстрактных если бы да кабы.
lazy load удобней, посещаемость не 10 000 000 человек, чтоб начинать экономить
lazy load удобней, посещаемость не 10 000 000 человек, чтоб начинать экономить
0
Чистый объект можно получить через какой-нибудь getClean() от объекта, а обновить объект через, допустим, reload(). Вместо этого фреймворк выделяет память под два объекта, да еще и делает два запроса.
Еще было бы неплохо использовать UnitOfWork, но вряд ли это впишется в текущию концепую, да и в ActiveRecord в часности
Еще было бы неплохо использовать UnitOfWork, но вряд ли это впишется в текущию концепую, да и в ActiveRecord в часности
0
Смысл может быть в том что нужена именно актуальная версия объекта, а не закешированная при первом вызове, вообще тема топика как-то высосана из пальца и наталкивает на то что ТС еще не совсем понял Yii.
Dr_Death твой пример совсем сомнителен и глуп по большей части, никто из нормальных разработчиков такое не поддержит, у тебя просто «глубокая обида» на то что твой «важный» патч не приняли?
Dr_Death твой пример совсем сомнителен и глуп по большей части, никто из нормальных разработчиков такое не поддержит, у тебя просто «глубокая обида» на то что твой «важный» патч не приняли?
-3
Ну наверно тогда проще дернуть один раз с параметром отключающем кэширование когда это действительно надо, чем постоянно дергать одно и тоже, когда это не надо. А дергать X раз parent для child->parent для вывода например ссылки на child, конечно не глупо. Обиды никакой, дописал руками и забыл про косяки, это проще и быстрей, чем слушать сказку про бычка.
0
ИМХО если Вам нужен IdentityMap, то у Вас проблемы в архитектуре приложения. Не понимаю зачем люди плодят название, если это по сути патерн Register…
Рекомендую почитать: «Патерны Проектирования» Гамма Эрик
Вы скрывает логику в защищенном методе, последующее поведение экземпляра класса не очевидно.
Рекомендую почитать: «Патерны Проектирования» Гамма Эрик
Вы скрывает логику в защищенном методе, последующее поведение экземпляра класса не очевидно.
-2
Identity Map нужен, чтобы без проблем вызывать всякие $user->getArticles() несколько раз не кешируя в переменную, да и просто вызывать ->findByPk($item_id) зная, что не будет лишнего запроса. Почему-то JPA, Hibernate, Entity Framework, Rails Activerecord этого придерживаются, но Yii упирается рожками.
0
По крайней мере в Rails эта штука по-умолчанию выключена. В комментариях написано «не включать, убьёт». В документации приведены примеры удаления лишних записей при включении.
0
Угу, только там проблема с ассоциациями. Для единой модели все очень даже живуче. Плюс рельсы еще и сам запрос скеширует id=`id`
0
Как раз оттого, что всё очень нетривиально для связей, этого ещё нет в Yii.
0
С чтением тут всё ясно и хорошо. Проблемы могу всплыть при записи.
0
Почему бы явно не положить объект в реестр?
Зачем мешать логику реестра и ектив рекорд? Будут потом проблемы с тестированием;
А если хотите вызывать $user->getArticles() создайте свойство $_articles;
$record = $someResponsibleObject->getRegister()->get(10);
if (!$record) {
$record = $repository->findByPk(10);
$someResponsibleObject->getRegister()->add($record->getId(), $record);
}
Зачем мешать логику реестра и ектив рекорд? Будут потом проблемы с тестированием;
А если хотите вызывать $user->getArticles() создайте свойство $_articles;
public function getArticles() {
if (!$this->_articles) {
$this->_articles = parent::getArticles();
}
return $this->_articles;
}
+1
Потому что хочется сохранить интерфейс нетронутым. Полиморфизм, знаете ли. Т.е.не клепать костыль при вызове, а изменить поведение, оставив интерфейс прежним.
>> Зачем мешать логику реестра и ектив рекорд?
Звучит как «зачем мешать mvc и?
>> Зачем мешать логику реестра и ектив рекорд?
Звучит как «зачем мешать mvc и?
-1
> Не понимаю зачем люди плодят название
В той же книге Гаммы Эрика написано, что многие паттерны очень похожи, но преследуют разные цели и из-за этого имеют разные названия (можно вспомнить про bridge/adapter/proxy из паттернов проектирования).
В той же книге Гаммы Эрика написано, что многие паттерны очень похожи, но преследуют разные цели и из-за этого имеют разные названия (можно вспомнить про bridge/adapter/proxy из паттернов проектирования).
+1
Эрих сотоварищи хотели как лучше, предположили, что будет рай, если дать каждому подходу по имени. Одного не учли эти парни с благими намерениями — есть в мире люди, тонко чувствующие всевозможные оттенки чего бы то ни было. А какой художник откажется дать имя, найденному им самим оттенку, ведь это шанс прикоснуться к великому!
+1
Столкнулся с одной проблемой. Большой расход памяти. Любой выбранный объект остаётся в оперативной памяти, так как мы не знаем, нужен ли нам будет ещё объект или нет, мы его все равно храним… типа, а вдруг понадобится.
+1
Угу, причем если вдруг понадобится, будь добр имей ссылку на этот объект, потому что выборка этих объектов повторно через ActiveRecord наплодит еще копий.
0
Как быть не знаешь? )
0
Я стараюсь сделать Service Layer, который как бы прослойка между контроллерами и моделями, и стараюсь не вызывать апи ActiveRecord кроме как из Service Layer, а из контроллера вызываю что-то типа $articleService->getLastArticles(5). Если память начнет быстро уходить или запросы станут тяжелыми, я всегда могу внутри метода сервиса переписать джоин через активрекорд на чистый sql или сделать кеширование в переменную.
Именно по причине тяги к энтерпрайз паттернам меня смущают виджеты, которые лезут в базу (помоему это противоречит даже MVC) и наличие знаний о базе и о маппинге в самой модели.
Именно по причине тяги к энтерпрайз паттернам меня смущают виджеты, которые лезут в базу (помоему это противоречит даже MVC) и наличие знаний о базе и о маппинге в самой модели.
+1
А у вас Service Layer наружу отдает объекты СActiveRecord?
Мне тоже нравится идея промежуточного слоя, но вот модели с их богатым интерфейсом несколько портят картину. Разделить бы CActiveRecord на Domain Model (CModel) и Data Mapper (CActiveFinder + insert/update логика).
Мне тоже нравится идея промежуточного слоя, но вот модели с их богатым интерфейсом несколько портят картину. Разделить бы CActiveRecord на Domain Model (CModel) и Data Mapper (CActiveFinder + insert/update логика).
0
Стараюсь всякие файндеры и прочую «статику» держать в сервисе, а отдавать — объект CActiveRecord. В методы модели стараюсь выносить всякие простые вещи вроде $article->getTopComments().
Насчет Domain Model это конечно уже к симфони + doctrine. Правда вот во всем этом кроется то, что мне не нравится в стаке PHP — все решения, перетянутые с JPA или рельсы выглядят громоздко. Субъективно, конечно.
Насчет Domain Model это конечно уже к симфони + doctrine. Правда вот во всем этом кроется то, что мне не нравится в стаке PHP — все решения, перетянутые с JPA или рельсы выглядят громоздко. Субъективно, конечно.
0
В Yii2 finder отдельно, модель отдельно.
0
Это хорошо. А насколько модель отдельно? Кто сохраняет изменения в БД, модель или finder? Модель знает что-нибудь про БД?
0
Sign up to leave a comment.
Реализация шаблона Identity Map в Yii Framework