жадная загрузка у загруженной модели

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Закрыто
caHek2x
Сообщения: 1242
Зарегистрирован: 2016.04.12, 20:41

жадная загрузка у загруженной модели

Сообщение caHek2x »

я уже задавал когда то этот вопрос ... но наверно не так сформулировав запутал только и поэтому не получил ответ ...
-----------------------------------
есть модель ... например Users
у нее есть связь Orders ...
public function getOrders()
{
return $this->hasMany(Orders::className(), ['user_id' => 'user_id']);
}
а у orders например есть связь Items ...
public function getItems()
{
return $this->hasMany(Items::className(), ['order_id' => 'order_id']);
}
-----------------------------------
я в курсе что чтоб это все вытянуть Users::find()->with("orders.items")->all...
но возьмем выдуманную ситуацию ...
получили мы $user = Users::find()->one();
не ту ли какого-то волшебного метода ... что-то типа:
AR::magicMethod($user, "orders.items");

чтоб сделать жадную загрузку в УЖЕ загруженной модели ... (НЕ при запроса а уже ПОСЛЕ запроса)
----------------------------------------------------
upd 18.01.2017 если кто столкнется с такой же проблемой: решил таким способом
Последний раз редактировалось caHek2x 2017.01.18, 17:29, всего редактировалось 1 раз.
Loveorigami
Сообщения: 977
Зарегистрирован: 2014.08.27, 21:54

Re: жадная загрузка у загруженной модели

Сообщение Loveorigami »

После запроса нужно все равно делать запрос, чтобы достать orders.
Как вариант - склонируй юзера для последующей выборки orders.
как в примере с пагинацией
http://www.yiiframework.com/doc-2.0/yii ... ation.html
caHek2x
Сообщения: 1242
Зарегистрирован: 2016.04.12, 20:41

Re: жадная загрузка у загруженной модели

Сообщение caHek2x »

После запроса нужно все равно делать запрос, чтобы достать orders.
я понимаю что при обращении $model->orders будет сделан запрос ... но меня волнует то что потом:
foreach (model->orders as $order) ...$order->items. ...
будет еще XX запросов равных количеству orders ...
а я бы хотел что yii прогрузило мне жадной выборкой .. .как оно это умеет ... where ... in (....
Как вариант - склонируй юзера для последующей выборки orders.
меня интересует вопрос именно в виде что мне пришла модель ... откуда угодно ... и чтоб я мог прогрузить то что мне надо ... так что о запросе забываем .. )
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: жадная загрузка у загруженной модели

Сообщение zelenin »

когда мы делаем with("orders.items"), у нас еще нет никаких данных, мы извлекаем orders, жадно грузим items и кладем их в orders.
В случае если у нас уже есть $model->orders, то это уже массив моделей с пустыми items, и мы не можем с ними работать в AR-стиле. Соответственно магия может быть только ручками:
$orderIds = ArrayHelper(...); //достаем все id заказов
$items = getItems($orderIds);
// группируем по orderId
// перебором распихиваем по order
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: жадная загрузка у загруженной модели

Сообщение zelenin »

caHek2x писал(а):откуда угодно
вообще "откуда угодно" - это ваш проект с вашим кодом.
caHek2x
Сообщения: 1242
Зарегистрирован: 2016.04.12, 20:41

Re: жадная загрузка у загруженной модели

Сообщение caHek2x »

zelenin писал(а):когда мы делаем with("orders.items"), у нас еще нет никаких данных, мы извлекаем orders, жадно грузим items и кладем их в orders.
В случае если у нас уже есть $model->orders, то это уже массив моделей с пустыми items, и мы не можем с ними работать в AR-стиле. Соответственно магия может быть только ручками:
$orderIds = ArrayHelper(...); //достаем все id заказов
$items = getItems($orderIds);
// группируем по orderId
// перебором распихиваем по order
да таким способом и делал ... но где то в AR нельзя этот механизм вытянуть ? ведь это предусмотрено (хоть и для другого "момента") ... просто ручками когда это одна вложенность да .. а если там вложенность на ->1->2->3->4->5 ...
мы извлекаем orders, жадно грузим items и кладем их в orders
ведь это тоже самое что и мне надо сделать ручками ...
Последний раз редактировалось caHek2x 2016.12.16, 18:01, всего редактировалось 1 раз.
caHek2x
Сообщения: 1242
Зарегистрирован: 2016.04.12, 20:41

Re: жадная загрузка у загруженной модели

Сообщение caHek2x »

zelenin писал(а):
caHek2x писал(а):откуда угодно
вообще "откуда угодно" - это ваш проект с вашим кодом.
я просто имел ввиду что не важно откуда пришла модель ... вернула ф-ция или мы сделали выборку или это модель из связи ...
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: жадная загрузка у загруженной модели

Сообщение zelenin »

caHek2x писал(а):
zelenin писал(а):когда мы делаем with("orders.items"), у нас еще нет никаких данных, мы извлекаем orders, жадно грузим items и кладем их в orders.
В случае если у нас уже есть $model->orders, то это уже массив моделей с пустыми items, и мы не можем с ними работать в AR-стиле. Соответственно магия может быть только ручками:
$orderIds = ArrayHelper(...); //достаем все id заказов
$items = getItems($orderIds);
// группируем по orderId
// перебором распихиваем по order
да таким способом и делал ... но где то в AR нельзя этот механизм вытянуть ? ведь это предусмотрено (хоть и для другого "момента") ... просто ручками когда это одна вложенность да .. а если там вложенность на ->1->2->3->4->5 ...
мы извлекаем orders, жадно грузим items и кладем их в orders
ведь это тоже самое что и мне надо сделать ручками ...
только ручками
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: жадная загрузка у загруженной модели

Сообщение zelenin »

caHek2x писал(а):
zelenin писал(а):
caHek2x писал(а):откуда угодно
вообще "откуда угодно" - это ваш проект с вашим кодом.
я просто имел ввиду что не важно откуда пришла модель ... вернула ф-ция или мы сделали выборку или это модель из связи ...
а я имею в виду, что вы имеете доступ к этому коду.
caHek2x
Сообщения: 1242
Зарегистрирован: 2016.04.12, 20:41

Re: жадная загрузка у загруженной модели

Сообщение caHek2x »

zelenin писал(а): 2016.12.16, 18:03 только ручками
появилось время, решил вернуться к данному вопросу ...
Решение моего вопроса:
https://yadi.sk/d/wzrHNuZK39dvUj
сделал, работает. во всяком случае на том что я протестировал все отлично.

Суть такая:
есть модель или массив моделей. Надо сделать жадную выборку каких-то связей
например есть массив моделей специальностей операторов

Код: Выделить всё

$models = Specialty::find()->limit(5)->all();
надо жадно загрузить операторов, операторы привязаны:

Код: Выделить всё

public function getOpers()
    {
        return $this->hasMany(Opers::className(), ['oper_id' => 'oper_id'])
            ->viaTable(OpersSpecialtyLink::tableName(), ['specialty_id' => 'specialty_id']);
    }
(да я понимаю что можно запросу дописать with, но суть именно в том что вот есть модели без with ... и надо прогрузить связи жадно ...)
моя ф-ция:

Код: Выделить всё

ModelHelper::loadWith($models, ['opers']);
или например

Код: Выделить всё

ModelHelper::loadWith($models, ['opers.permission']);
ф-ция loadWith сделает два запрос:

Код: Выделить всё

SELECT `specialty_id`, `oper_id` FROM `opers_specialty_link` WHERE specialty_id in (-1,2,4,5,6)
и

Код: Выделить всё

SELECT * FROM `opers` WHERE oper_id in (10,14,115,287,8,71,196,268,292,279,317,333,339,356,134,337,340,348,306,236,234,82,235,238,63,136,7,207,306,236,234,235,220,348,7,94,238,318,134)
и разложит все по моделям ...

если у модели уже была загружена связь - loadWith заново грузить и трогать её не будет ...
если у модели getter возвращает null то тоже трогать не будет ...
проверку на null сделал для таких целей, бывают такие связи:

Код: Выделить всё

public function getSegment()
    {
        if ($this->link_type == self::LINK_TYPE_SEGMENT) return $this->hasOne(MapSegments::className(), ['seg_id' => 'link_val1']);
        else return null;
    }
еще бы по хорошему обработать inverseOf ... но пока еще руки не дошли ...
------------------------------
может я сделал велосипед никому не нужный ... но я не нашел альтернативы для такой задачи
Последний раз редактировалось caHek2x 2017.01.18, 16:17, всего редактировалось 1 раз.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: жадная загрузка у загруженной модели

Сообщение zelenin »

никому не нужно. все работают со своим кодом, в котором можно поставить with. Ваша ситуация - это попытка усложнить себе жизнь.
caHek2x
Сообщения: 1242
Зарегистрирован: 2016.04.12, 20:41

Re: жадная загрузка у загруженной модели

Сообщение caHek2x »

ситуации бывают разные ... в некоторых моментах проще догрузить данные чем вставить with в запрос ... да и ситуация что самое последнее описано: "проверку на null сделал для таких целей, бывают такие связи:"
я один с такими связями ? таких ситуаций не бывает ? ... стандартный with с этим не справляется ...
----------------
или например выдуманная ситуация есть модели пользователей .. .и надо в списке выводить адрес если баланс меньше 0 ... грузить для всех with адреса ? или грузить отдельно тех у кого баланс меньше 0 и больше ... а так можно загрузить всех без with .. .а потом только нужным догрузить связи ...
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: жадная загрузка у загруженной модели

Сообщение zelenin »

caHek2x писал(а): 2017.01.18, 16:08 ситуации бывают разные ... в некоторых моментах проще догрузить данные чем вставить with в запрос ...
не бывает таких ситуаций
caHek2x писал(а): 2017.01.18, 16:08да и ситуация что самое последнее описано: "проверку на null сделал для таких целей, бывают такие связи:"
я один с такими связями ? таких ситуаций не бывает ? ... стандартный with с этим не справляется ...
я не понимаю этого кейса
caHek2x
Сообщения: 1242
Зарегистрирован: 2016.04.12, 20:41

Re: жадная загрузка у загруженной модели

Сообщение caHek2x »

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

Код: Выделить всё

    /*LINK_TYPE_HOUSE*/
    public function getHouse()
    {
        if ($this->link_type == self::LINK_TYPE_HOUSE) return $this->hasOne(MapHouses::className(), ['house_id' => 'link_val1']);
        else return null;
    }

    /*LINK_TYPE_STREET*/
    public function getStreet()
    {
        if ($this->link_type == self::LINK_TYPE_STREET) return $this->hasOne(MapStreets::className(), ['street_id' => 'link_val1']);
        else return null;
    }

    /*LINK_TYPE_SEGMENT*/
    public function getSegment()
    {
        if ($this->link_type == self::LINK_TYPE_SEGMENT) return $this->hasOne(MapSegments::className(), ['seg_id' => 'link_val1']);
        else return null;
    }

    /*LINK_TYPE_AREA*/
    public function getArea()
    {
        if ($this->link_type == self::LINK_TYPE_AREA) return $this->hasOne(MapAreas::className(), ['area_id' => 'link_val1']);
        else return null;
    }
вот как потом догрузил

Код: Выделить всё

ModelHelper::loadWith($all, ['items.area', 'items.segment', 'items.street', 'items.house.street', 'items.fm', 'items.switch', 'items.childrens.switch']);
со стандартным with такого чуда не выйдет ...
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: жадная загрузка у загруженной модели

Сообщение zelenin »

этот кейс решается созданием NullActiveQuery, реализующий ActiveQueryInterface, который будет возвращаться вместо null.

Код: Выделить всё

public function getSwitch()
{
    if ($this->link_type == self::LINK_TYPE_SWITCH || $this->link_type == self::LINK_TYPE_SWITCH_DN || $this->link_type == self::LINK_TYPE_PORT) {
        return $this->hasOne(Switchh::className(), ['CODE' => 'link_val1']);
    } else {
        return new NullActiveQuery;
    }
}
caHek2x
Сообщения: 1242
Зарегистрирован: 2016.04.12, 20:41

Re: жадная загрузка у загруженной модели

Сообщение caHek2x »

zelenin писал(а): 2017.01.18, 16:36 этот кейс решается созданием NullActiveQuery, реализующий ActiveQueryInterface, который будет возвращаться вместо null.

Код: Выделить всё

class NullActiveQuery implements ActiveQueryInterface
чтото в нем надо прописывать ? (ide заполнила пустыми методами ... )
upd дописал еще пустой populateRelation заработало ... буду знать, такого кейса не знал )
но это все равно не отменяет необходимость того что выше написал )
upd работало на одной модели ... но при выборке нескольких моделей чтото жадная загрузка вообще не отработала ... в вашем NullActiveQuery чтото еще надо прописать ?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: жадная загрузка у загруженной модели

Сообщение zelenin »

caHek2x писал(а): 2017.01.18, 16:49
zelenin писал(а): 2017.01.18, 16:36 этот кейс решается созданием NullActiveQuery, реализующий ActiveQueryInterface, который будет возвращаться вместо null.

Код: Выделить всё

class NullActiveQuery implements ActiveQueryInterface
чтото в нем надо прописывать ? (ide заполнила пустыми методами ... )
то, что необходимо для решения проблемы. возвращать null например на ->one(), или пустой массив на all(), или не выполнять запросы, там где не нужно
caHek2x писал(а): 2017.01.18, 16:49upd дописал еще пустой populateRelation заработало ... буду знать, такого кейса не знал )
но это все равно не отменяет необходимость того что выше написал )
upd работало на одной модели ... но при выборке нескольких моделей чтото жадная загрузка вообще не отработала ...
это у вас что-то не работает.
caHek2x
Сообщения: 1242
Зарегистрирован: 2016.04.12, 20:41

Re: жадная загрузка у загруженной модели

Сообщение caHek2x »

перепроверил ... да работает частично ...
у некоторых оно сделало жадную загрузку а большую часть пропустило ...
upd: случайно там не берется по первой модели ... и на связь остальных моделей не смотрится ? и соответственно если в первой у меня NullActiveQuery то оно и не возвращает ничего для всех моделей ... ?!
upd: если так понял исходник то оно так и делает ...
upd: так что в любом случае от того что я написал смысл и польза есть :)
Nerf
Сообщения: 780
Зарегистрирован: 2015.01.29, 00:37

Re: жадная загрузка у загруженной модели

Сообщение Nerf »

У вас не вызывается релейшены для каждой модели, соответственно все $this в релейшенах не актуальны. Связи кривые изначально, методы должны возвращать ActiveQueryInterface, поэтому вам предложили реализовать NullObject.
Ваши релейшены вообще работают при стандартных возовах with()?
caHek2x
Сообщения: 1242
Зарегистрирован: 2016.04.12, 20:41

Re: жадная загрузка у загруженной модели

Сообщение caHek2x »

Nerf писал(а): 2017.01.18, 21:12 У вас не вызывается релейшены для каждой модели, соответственно все $this в релейшенах не актуальны. Связи кривые изначально, методы должны возвращать ActiveQueryInterface, поэтому вам предложили реализовать NullObject.
Ваши релейшены вообще работают при стандартных возовах with()?
я вас немного не понял ... все релейшины работают замечательно ... просто если делать жадную выборку для массива моделей (all) то как вы и я выше написал используется релейшин только первой модели для всех... то есть для стандартных ситуаций это нормально ... но когда связь привязана к какимто данным this обьекта (link_type) это(жадная загрузка) работать не будет ... ... и поэтому я написал свою ф-цию для выборки после загрузки ... с учетом null ... ну и не только для этого иногда и просто пригождается догрузить у готовой модели ...
--------------------------
upd: я думаю обсуждать далее по этой теме нет смысла ... все выше было обсуждено ... ктото считает это велосипедом ... я, не найдя альтернативы, считаю это решением определенного рода задачи ... исходник я выложил может кому пригодится ... ну а если нет то в любом случае делал для себя ... благодарю всех за участие :)
Закрыто