Запросы к отношениям Many-to-many

Общие вопросы по использованию фреймворка. Если не знаете как что-то сделать и это про Yii, вам сюда.
orkon
Сообщения: 8
Зарегистрирован: 2010.05.07, 14:06
Контактная информация:

Запросы к отношениям Many-to-many

Сообщение orkon »

Есть три таблицы - игры, типы игр и таблица gb_games_types обеспечивает отношение многие-ко-многим. Нужно получить все игры, указанного типа:

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

CREATE TABLE `gb_games` (
  `g_id` int(11) NOT NULL,
  PRIMARY KEY  (`g_id`)
)
CREATE TABLE `gb_games_types` (
  `gt_game_id` int(11) NOT NULL,
  `gt_type_id` int(11) NOT NULL,
  PRIMARY KEY  (`gt_game_id`,`gt_type_id`)
)

CREATE TABLE `gb_types` (
  `t_id` int(11) NOT NULL auto_increment,
  `t_name` varchar(45) character set utf8 default NULL,
  PRIMARY KEY  (`t_id`)
) 
Вот такой я написал код для этого:

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

public function actionType() {
        $type = null;

        if (!(isset($_GET['type_id']) && is_numeric($_GET['type_id']))) {
            return;
        }
        
        $criteria=new CDbCriteria;
        $criteria->condition = 't_id=:t_id';
        $criteria->params = array(':t_id'=>$_GET['type_id']);

        $pages=new CPagination(Types::model()->with('gb_games')->count($criteria));
        $pages->pageSize=self::PAGE_SIZE;
        $pages->applyLimit($criteria);


        $models=Types::model()->with('gb_games')->findAll($criteria);

        if (empty($models)) {
            throw new CHttpException(404,'The requested page does not exist.');
        }

        foreach ($models as $key=>$type) {
            $cr=new CDbCriteria;
            $cr->condition = 'gt_type_id=:t_id';
            $cr->params = array(':t_id'=>$type->t_id);
            $models = Games::model()->with('gb_types')->findAll($cr);
        }

        $this->render('list',array(
            'models'=>$models,
            'pages'=>$pages,
            'type'=>$type
        ));
    } 
И в этом методе ошибка происходит: CDbCommand не удалось исполнить SQL-запрос: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'gt_type_id' in 'where clause'

Не могу понять, как правильно записать условие, чтобы произошла выборка игр. Подскажите, пожалуйста.
Спасибо.
May the force be with you.
Аватара пользователя
IceDragon
Сообщения: 50
Зарегистрирован: 2010.04.08, 20:02

Re: Запросы к отношениям Many-to-many

Сообщение IceDragon »

выведи SQL и посмотри что в нем неправильно.
orkon
Сообщения: 8
Зарегистрирован: 2010.05.07, 14:06
Контактная информация:

Re: Запросы к отношениям Many-to-many

Сообщение orkon »

IceDragon писал(а):выведи SQL и посмотри что в нем неправильно.
Подскажите, как вывести SQL, пожалуйста
May the force be with you.
Аватара пользователя
timlar
Сообщения: 1382
Зарегистрирован: 2009.09.19, 17:49
Откуда: Украина, Днепропетровск
Контактная информация:

Re: Запросы к отношениям Many-to-many

Сообщение timlar »

В конфиге настрой профайлер:

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

        'log'=>array(
            'class'=>'CLogRouter',
            'routes'=>array(
                . . .
                // -- CProfileLogRoute -------------------------------
                array(
                    'class'=>'CProfileLogRoute',
                    'levels'=>'profile',
                    'enabled'=>true,
                ),
                // -------------------------------------------------------
                . . .
            ),
        ), 
Затем смотри внизу страницы :)
Последний раз редактировалось timlar 2010.05.07, 14:39, всего редактировалось 1 раз.
Twitter: @timlar_ua
Аватара пользователя
IceDragon
Сообщения: 50
Зарегистрирован: 2010.04.08, 20:02

Re: Запросы к отношениям Many-to-many

Сообщение IceDragon »

поставь себе

http://www.yiiframework.com/extension/yiidebugtb/

она показывает всю статистику по загруженной странице )
но выводит даже инфу по подключению к БД
Аватара пользователя
IceDragon
Сообщения: 50
Зарегистрирован: 2010.04.08, 20:02

Re: Запросы к отношениям Many-to-many

Сообщение IceDragon »

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

* 1. First Step.
 * Extract yiidebugtb folder to [webroot]/protected/extensions/yiidebugtb
 * --Test:
 * -- You must have an "[webroot]/protected/extensions/yiidebugtb/XWebDebugRouter.php" file
 * -- if you all right way.
 *
 * 2. Second Step.
 * Open [webroot]/protected/config/main.php, find section 'import' and add following lines which belongs to yiidebugtb:
 *
 * [...]
 * // autoloading model and component classes
 * 'import'=>array(
 *    'application.models.*',
 *    'application.extensions.yiidebugtb.*'
 *    [...]
 * ),
 * [...]
 *
 * 3. And Last Step.
 * In [webroot]/protected/config/main.php find section 'routes' and add following lines for XWebDebugRouter:
 *
 * [...]
 * 'routes'=>array(
 *    array(
 *      'class'=>'XWebDebugRouter',
 *      'config'=>'alignLeft, opaque, runInDebug, fixedPos, collapsed',
 *      'levels'=>'error, warning, trace, profile, info'
 *    ),
 * ),
 * [...]
 
это настройки
Последний раз редактировалось IceDragon 2010.05.07, 14:40, всего редактировалось 1 раз.
Аватара пользователя
timlar
Сообщения: 1382
Зарегистрирован: 2009.09.19, 17:49
Откуда: Украина, Днепропетровск
Контактная информация:

Re: Запросы к отношениям Many-to-many

Сообщение timlar »

IceDragon писал(а):поставь себе

http://www.yiiframework.com/extension/yiidebugtb/

она показывает всю статистику по загруженной странице )
но выводит даже инфу по подключению к БД
Не, не надо ее ставить :) Это зло :lol: Меня в этом Сэм переубедил :oops:
Twitter: @timlar_ua
Аватара пользователя
IceDragon
Сообщения: 50
Зарегистрирован: 2010.04.08, 20:02

Re: Запросы к отношениям Many-to-many

Сообщение IceDragon »

тык на продакшн никто и не предлагает.
для дебага самое то.
Аватара пользователя
timlar
Сообщения: 1382
Зарегистрирован: 2009.09.19, 17:49
Откуда: Украина, Днепропетровск
Контактная информация:

Re: Запросы к отношениям Many-to-many

Сообщение timlar »

IceDragon писал(а):тык на продакшн никто и не предлагает.
для дебага самое то.
Для дебага хватает и CWebLogRoute или CProfileLogRoute :)
Twitter: @timlar_ua
orkon
Сообщения: 8
Зарегистрирован: 2010.05.07, 14:06
Контактная информация:

Re: Запросы к отношениям Many-to-many

Сообщение orkon »

Вот такой sql:

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

SELECT `t`.`g_id` AS `t0_c0`, `t`.`g_rate` AS `t0_c1`, `t`.`g_name_url` AS `t0_c2`, 
`t`.`g_type` AS `t0_c3`, `t`.`g_added` AS `t0_c4`, `t`.`g_size` AS `t0_c5`, 
`t`.`g_name` AS `t0_c6`, `t`.`g_medium_pic` AS `t0_c7`, `t`.`g_small_pic` AS `t0_c8`, 
`t`.`g_download_link` AS `t0_c9`, `t`.`g_shortdescr` AS `t0_c10`, `t`.`g_fulldescr` AS `t0_c11`, 
`t`.`g_publish_date` AS `t0_c12`, `t`.`g_state` AS `t0_c13`
FROM `gb_games` `t` 
WHERE (gt_type_id=:t_id) 
Данные выбираются только из games, хотя with вроде должен присоединить таблицу с типам?
May the force be with you.
Аватара пользователя
timlar
Сообщения: 1382
Зарегистрирован: 2009.09.19, 17:49
Откуда: Украина, Днепропетровск
Контактная информация:

Re: Запросы к отношениям Many-to-many

Сообщение timlar »

Дай код самой реляции gb_games
Twitter: @timlar_ua
orkon
Сообщения: 8
Зарегистрирован: 2010.05.07, 14:06
Контактная информация:

Re: Запросы к отношениям Many-to-many

Сообщение orkon »

Timlar писал(а):Дай код самой реляции gb_games

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

// Games model
public function relations()
    {
        // NOTE: you may need to adjust the relation name and the related
        // class name for the relations automatically generated below.
        return array(
            'gb_types' => array(self::MANY_MANY, 'Types', 'gb_games_types(gt_game_id, gt_type_id)','together'=>false,'joinType'=>'INNER JOIN'),
            'gb_screenshots' => array(self::HAS_MANY, 'Screenshots', 's_game_id'),
        );
    } 

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

//Types model
public function relations()
    {
        // NOTE: you may need to adjust the relation name and the related
        // class name for the relations automatically generated below.
        return array(
            'gb_games' => array(self::MANY_MANY, 'Games', 'gb_games_types(gt_game_id, gt_type_id)', 'together'=> true ),
        );
    } 
Вот
May the force be with you.
orkon
Сообщения: 8
Зарегистрирован: 2010.05.07, 14:06
Контактная информация:

Re: Запросы к отношениям Many-to-many

Сообщение orkon »

В общем, к чему я пришел:

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

public function actionType() {
        $type = null;

        if (!(isset($_GET['type_id']) && is_numeric($_GET['type_id']))) {
            return;
        }
        
        $criteria=new CDbCriteria;
        $criteria->condition = 't_id=:t_id';
        $criteria->params = array(':t_id'=>$_GET['type_id']);

        $type = Types::model()->find($criteria);


        $cr=new CDbCriteria;
        $cr->distinct = true;
        $cr->condition = 'gt_type_id=:t_id';
        $cr->order = 'g_added DESC';
        $cr->params = array(':t_id'=>$type->t_id);

        echo Games::model()->with('gb_types')->count($cr);

        $pages=new CPagination(Games::model()->with('gb_types')->count($cr));
        $pages->pageSize=self::PAGE_SIZE;
        $pages->applyLimit($cr);

        $models = Games::model()->with('gb_types')->findAll($cr);

        $this->render('list',array(
            'models'=>$models,
            'pages'=>$pages,
            'type'=>$type
        ));
    } 
Этот код работает правильно, если убрать создания страниц - создается такой запрос:

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

SELECT DISTINCT `t`.`g_id` AS `t0_c0`, `t`.`g_rate` AS `t0_c1`, `t`.`g_name_url` AS `t0_c2`, `t`.`g_type` AS `t0_c3`, `t`.`g_added` 
AS `t0_c4`, `t`.`g_size` AS `t0_c5`, `t`.`g_name` AS `t0_c6`, `t`.`g_medium_pic` AS `t0_c7`, `t`.`g_small_pic` AS `t0_c8`, 
`t`.`g_download_link` AS `t0_c9`, `t`.`g_shortdescr` AS `t0_c10`, `t`.`g_fulldescr` AS `t0_c11`, `t`.`g_publish_date` AS `t0_c12`, 
`t`.`g_state` AS `t0_c13`, `gb_types`.`t_id` AS `t1_c0`, `gb_types`.`t_name` AS `t1_c1` FROM `gb_games` `t` INNER JOIN 
`gb_games_types` `gb_types_gb_types` ON (`t`.`g_id`=`gb_types_gb_types`.`gt_game_id`) INNER JOIN `gb_types` `gb_types` ON 
(`gb_types`.`t_id`=`gb_types_gb_types`.`gt_type_id`) WHERE (gt_type_id=:t_id) ORDER BY g_added DESC
Если страницы оставить, то всё ломается - накладывается лимит и офсет, но не происходит join:

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

SELECT DISTINCT `t`.`g_id` AS `t0_c0`, `t`.`g_rate` AS `t0_c1`, `t`.`g_name_url` AS `t0_c2`, `t`.`g_type` AS `t0_c3`, `t`.`g_added` 
AS `t0_c4`, `t`.`g_size` AS `t0_c5`, `t`.`g_name` AS `t0_c6`, `t`.`g_medium_pic` AS `t0_c7`, `t`.`g_small_pic` AS `t0_c8`, 
`t`.`g_download_link` AS `t0_c9`, `t`.`g_shortdescr` AS `t0_c10`, `t`.`g_fulldescr` AS `t0_c11`, `t`.`g_publish_date` AS `t0_c12`, 
`t`.`g_state` AS `t0_c13` FROM `gb_games` `t` WHERE (gt_type_id=:t_id) ORDER BY g_added DESC LIMIT 10
Поэтому поля и недоступны. Как это исправить или обойти??
May the force be with you.
Аватара пользователя
IceDragon
Сообщения: 50
Зарегистрирован: 2010.04.08, 20:02

Re: Запросы к отношениям Many-to-many

Сообщение IceDragon »

как я вижу
$cr->params = array(':t_id'=>$type->t_id);
у тебя не срабатывает - в SQL - WHERE (gt_type_id=:t_id)
orkon
Сообщения: 8
Зарегистрирован: 2010.05.07, 14:06
Контактная информация:

Re: Запросы к отношениям Many-to-many

Сообщение orkon »

Всё вроде срабатывает, пока я не устанавливаю $cr поля limit и offset. То есть сейчас реляционный запрос работает, но я не могу разбить его на страницы.
May the force be with you.
Аватара пользователя
timlar
Сообщения: 1382
Зарегистрирован: 2009.09.19, 17:49
Откуда: Украина, Днепропетровск
Контактная информация:

Re: Запросы к отношениям Many-to-many

Сообщение timlar »

Я вот не пойму логику. У каждой игры может быть несколько типов? Если нет, то какой смысл делать связь многие-ко-многим?
Twitter: @timlar_ua
orkon
Сообщения: 8
Зарегистрирован: 2010.05.07, 14:06
Контактная информация:

Re: Запросы к отношениям Many-to-many

Сообщение orkon »

Timlar писал(а):Я вот не пойму логику. У каждой игры может быть несколько типов? Если нет, то какой смысл делать связь многие-ко-многим?
да, у каждой игры может быть несколько типов. Вообще типы - это жанры игр.
May the force be with you.
Werewolf
Сообщения: 98
Зарегистрирован: 2010.02.27, 14:37
Контактная информация:

Re: Запросы к отношениям Many-to-many

Сообщение Werewolf »

limit и offset в 99% не имеют смысла если MANY_MANY дергается через один большой запрос.
CDBcriteria разбивает запросы, остается насильно заджойнить таблицу($cr->join) и сгруппировать($cr->groupby) по ID основной.
Как фильтровать такие данные я написал в посте.
youroff
Сообщения: 228
Зарегистрирован: 2010.02.25, 16:05

Re: Запросы к отношениям Many-to-many

Сообщение youroff »

Werewolf писал(а):limit и offset в 99% не имеют смысла если MANY_MANY дергается через один большой запрос.
CDBcriteria разбивает запросы, остается насильно заджойнить таблицу($cr->join) и сгруппировать($cr->groupby) по ID основной.
Как фильтровать такие данные я написал в посте.
Почитал пост... в общем здорово, но все равно не совсем понятно. Ты мог бы расширить эту статью? Тогда можно будет выложить ее в рецепты...
Например, не понятно, зачем ты в статье создаешь две связи genres и genres2. Вернее по описанию выходит, что одну для вывода жанров вместе с фильмами, а вторую для фильтрации. Но в конце показан один пример использования. И не понятно, какие в итоге поля попадают в CListView. В общем, было бы круто расписать все подробнее.
Я просто сейчас как раз голову ломаю на сращивании реляций MANY_MANY и CActiveDataProvider
Werewolf
Сообщения: 98
Зарегистрирован: 2010.02.27, 14:37
Контактная информация:

Re: Запросы к отношениям Many-to-many

Сообщение Werewolf »

Дополнил статью, второе отношение выкинул как ресурсоемкое и ненужное.
Ответить