Использование through

Предварительное обсуждение найденных ошибок перед отправкой их авторам фреймворка, а также внесение новых предложений.
Ответить
Аватара пользователя
Caveman
Сообщения: 152
Зарегистрирован: 2009.04.04, 20:56
Откуда: Москва
Контактная информация:

Использование through

Сообщение Caveman »

Обычная ситуация:
Есть модель категорий, включающих подкатегории (2 уровня и не больше), есть продукция, приписываемая некоторой категории. Хочется выводить для родительских категорий все товары, приписанные категориям-потомкам.

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

public function relations() {
        return array(
    'children' => array(self::HAS_MANY, 'Category', 'parent_id'),
    'products' => array(self::HAS_MANY, 'Product', 'category_id'),
    'allProducts' => array(self::HAS_MANY, 'Product', 'category_id', 'through' => 'children')
        );
    } 
Можно делать как в этой теме - http://www.yiiframework.ru/forum/viewto ... f=3&t=3744 , но как-то некошерно, ведь есть ключевое слово "through", вроде бы служащее как раз именно для таких случаев.
Попытка его использования приводит к неправильному запросу (причем, на оффоруме уже есть пару схожих тем), а именно - в сгенерированном запросе связь получается такой - category.category_id = product.id , а не category.category_id = product.category_id , как должно быть. Видно, что объект внешнего ключа и объект первичного ключа поменяны местами.

Покопавшись в коде фреймворка дошел до этого кода: (CActiveFinder.php, lines 643-652)

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

if($element->slave->slave===null)
    {
        $fke=$element->slave;
        $pke=$element;
    }
    else // nested through detected
    { // <------ в случае использования through сюда не попадаем, хотя по идее должны. Нету этого объекта - $element->slave->slave
        $fke=$element;
        $pke=$element->slave;
    } 
Добавка проверки (все-таки считаю хаком, а не решением):

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

if($element->slave->slave===null && $element->slave->relation->select)
    {
        $fke=$element->slave;
        $pke=$element;
    }
    else // nested through detected
    { // <------ а теперь попадаем, т.к. при использовании through из промежуточной таблицы не берутся никакие поля, т.е., $element->slave->relation->select - пусто
        $fke=$element;
        $pke=$element->slave;
    } 
решает проблему и получаем правильный запрос.

Теперь вопрос - такое поведение только для данного случая или же для других вариантов связей при использовании through ? Кто-нибудь уже использовал успешно through ?

З.Ы. В документации по-моему какие-то нестыковки в разделе о through - там то вторичный ключ фигурирует в связи с through, то первичный...
Аватара пользователя
creocoder
Сообщения: 138
Зарегистрирован: 2010.01.24, 05:29
Откуда: Тамбов

Re: Использование through

Сообщение creocoder »

В вашем случае использовать through не нужно. Для успешного использования through необходимо наличие 3-ех таблиц, одна из которых ассоциативная. Есть одно исключение, оно хорошо описано в Guide. Остальные случаи при которых использовать through есть смысл, тоже хорошо описаны. В чем затруднение получить желаемое например так?

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

Category::model()->with('children.products')->findAll();
 
Аватара пользователя
Caveman
Сообщения: 152
Зарегистрирован: 2009.04.04, 20:56
Откуда: Москва
Контактная информация:

Re: Использование through

Сообщение Caveman »

creocoder писал(а):В чем затруднение получить желаемое например так?

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

Category::model()->with('children.products')->findAll();
 
Вполне можно получить через with, но эксперименты никто не отменял.

Значит, through - это, по сути, связь многие-ко-многим с промежуточной моделью (за исключением HAS_ONE)?

По-моему, в guide стоит начать с назначения through, в каких случаях целесообразно его применять. Сейчас это неочевидно.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Использование through

Сообщение samdark »

Да, про неочевидность факт. Уже думаем, как лучше подать это дело.
Аватара пользователя
Svyatov
Сообщения: 459
Зарегистрирован: 2010.08.12, 14:50
Откуда: Санкт-Петербург
Контактная информация:

Re: Использование through

Сообщение Svyatov »

Поддержу Caveman. Сначала показалось прикольно, но когда и для чего это лучше применять не понятно.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Использование through

Сообщение samdark »

Применять стоит прежде всего когда нужен MANY_MANY и при этом нужно вытаскивать данные из таблицы-связки.
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Использование through

Сообщение slavcodev »

Sam Dark писал(а):Применять стоит прежде всего когда нужен MANY_MANY и при этом нужно вытаскивать данные из таблицы-связки.
Вот ничего себе ) можно с таблицы связки данные брать? Как раз на днях нужно было ( жаль что в документации об этом мало написано.
Жду Yii 3!
Аватара пользователя
Caveman
Сообщения: 152
Зарегистрирован: 2009.04.04, 20:56
Откуда: Москва
Контактная информация:

Re: Использование through

Сообщение Caveman »

По сути, никто не мешает задать связь через промежуточную таблицу, имеющую модель.
Пока не могу понять конкретного назначения through.

Пока разбирался с through, вычитал, что в ruby есть полиморфные связи. Вот это было бы неплохо реализовать.
Ekstazi
Сообщения: 1428
Зарегистрирован: 2009.08.20, 22:54
Откуда: Молдова, Бельцы
Контактная информация:

Re: Использование through

Сообщение Ekstazi »

Полиморфные - это как ? о_О
Аватара пользователя
Caveman
Сообщения: 152
Зарегистрирован: 2009.04.04, 20:56
Откуда: Москва
Контактная информация:

Re: Использование through

Сообщение Caveman »

Ekstazi писал(а):Полиморфные - это как ? о_О
http://www.rusrails.ru/active-record-as ... ciations-2

Хотя... Это несложно сделать и сейчас.
Ekstazi
Сообщения: 1428
Зарегистрирован: 2009.08.20, 22:54
Откуда: Молдова, Бельцы
Контактная информация:

Re: Использование through

Сообщение Ekstazi »

спс
chuev
Сообщения: 1
Зарегистрирован: 2013.06.11, 08:11
Откуда: Харьков
Контактная информация:

Re: Использование through

Сообщение chuev »

И всё таки, ситуация... Есть модель категории с подкатегориями и товарами:

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

public function relations()
{
    return array(
        'parent' => array(self::BELONGS_TO, 'Category', 'parent_id'),
        'children' => array(self::HAS_MANY, 'Category', 'parent_id'),
        'products' => array(self::MANY_MANY, 'Product', 'product_category(category_id, product_id)'),
        'allProducts' => array(self::MANY_MANY, ???, 'through' => 'children'),
    );
} 
Как получить все товары для родительских категорий, используя through?
Аватара пользователя
creocoder
Сообщения: 138
Зарегистрирован: 2010.01.24, 05:29
Откуда: Тамбов

Re: Использование through

Сообщение creocoder »

chuev писал(а):И всё таки, ситуация... Есть модель категории с подкатегориями и товарами:

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

public function relations()
{
    return array(
        'parent' => array(self::BELONGS_TO, 'Category', 'parent_id'),
        'children' => array(self::HAS_MANY, 'Category', 'parent_id'),
        'products' => array(self::MANY_MANY, 'Product', 'product_category(category_id, product_id)'),
        'allProducts' => array(self::MANY_MANY, ???, 'through' => 'children'),
    );
}
Как получить все товары для родительских категорий, используя through?
У MANY_MANY нет опции through. Разбивайте MANY_MANY на 2 HAS_MANY, делайте для ассоциативной таблицы (product_category) модель и тогда всё получится.
Ответить