Cdbcriteria И Сложные Sql-Запросы

всем привет

народ, просветите: возможно ли в сидибикрайтериа сформировать сложный sql-запрос?

типа, вложенные в where, вложенные в select, left join с using?

есть примеры?

пол минуты думал что это за слово, не надо так, пожалуйста :)

Сложный запрос наверное можно. Но насколько я помню из опыта, по читаемости он получается хуже чем чистый SQL.

Примера так не найду, лучше покажите какой запрос вы хотите выразить через PDO.

+100.

Вообще, такие штуки, кмк, проще всего писать на sql и запихивать в модель.

Из контроллера уже вызывать готовый метод.

ну например такой =

SELECT COUNT(keyword) AS relevance, i.id, d.title

FROM Index i

JOIN Documents d ON (i.id=d.id) WHERE d.id IN ( SELECT id FROM Index WHERE keyword = ‘word’ )

GROUP BY id ORDER BY relevance DESC




$result=Yii::app()->db->createCommand()

->select('COUNT(keyword) AS relevance, i.id, d.title')

->from('Index i')

->join('Documents d','i.id=d.id')

->where('d.id IN ( SELECT id FROM Index WHERE keyword = :keyword )')

->group('i.id')

->order('relevance DESC')

->bindParam(':keyword',$keyword,PDO::PARAM_STR)

->queryAll();



Ну или на чистом SQL. Мне сложные запросы проще писать на чистом, но когда лучше быстро и в 1 строчку, лучше command builder.

Насчет контроллеров это верно, там не должно быть работы с БД.

так-так-так…

можно поподробнее?

пока, в моем понимании модель всегда связана с одной таблицей

и как запихнуть в такую однотабличную модель sql-запрос написанный привычным (строчным)способом?

можете показать - если не сложно?

спасибо!

но меня эта тема заинтересовала исходя из использования criteria в CActiveDataProvider

мне и самому куда больше нравится писать на родном sql-ле

в общем вот что у меня получилось =


/*

SELECT *

FROM `page` 

JOIN `page_meta`

USING(`id_page`) 

*/

$crit = new CDbCriteria();

$crit->select = "title";

$crit->join = "JOIN `page_meta` USING(`id_page`)";

$crit->order = "title ASC";




/*

SELECT *

FROM `page` 

JOIN `page_meta`

USING(`id_page`)  

WHERE `id_page` = (

    SELECT `id_page` FROM `page` 

    WHERE `link` = 'politic-first'

    )

*/

$crit = new CDbCriteria();

$crit->select = "title";

$crit->join = "JOIN `page_meta` USING(`id_page`)";

$crit->condition = "`id_page` = (SELECT `id_page` FROM `page` ";

$crit->condition .= " WHERE `link` = 'politic-first')";

$crit->order = "title ASC";


$dataProvider=new CActiveDataProvider('Page',array(

	'criteria'=>$crit,

	'countCriteria'=>$crit,                    

	'pagination'=>array(

		'pageSize'=>2,

	),                    

));

p.s. можно это как-то еще соптимизировать?

Насчет оптимизировать вряд ли подскажу.

В моделе можно сделать статический метод, в нем делать запросы к множеству таблиц и возвращать массив AR, или массив данных, или что там удобно. Ну и вызывать такой метод в контроллерах.

Но некоторые считают, в ActiveRecord должны быть только методы доступа к данным и по минимуму бизнес логики, конечно нужно еще определиться с понятием "бизнес логики". Но если вас будет беспокоить чистота ваших моделей, можно создать новый класс, и разместить код получения данных в нем. Кажется такие классы называют "сервисами", и хранить их можно все в той же папке моделей.

меня скорее беспокоит некое соответствие писано-неписанным стандартам работы с ООП чем чистота моделей…

а что касается отдельного класса для получения данных - так обычно всегда и делал, но всегда казалось, что это как-то не по ооповски-иишно :unsure:

Насчет оптимизировать это что оптимизировать?

Запрос - возможно если будут большие таблицы, убрать join и добавить индексы (ну это нужно все проверять, что будет быстрее). На мелких таблицах не имеет смысла если скорость устраивает.

Код оптимизировать некуда)

Насчет модели это верно. Нужно делать методы для получения данных. Иногда приходится и не статические, иногда геттеры и сеттеры, но в основном я пользуюсь статическими.

Собственно говоря берете ваш код и делаете как то так:




public static function getMyProvider()

{

/*

SELECT *

FROM `page` 

JOIN `page_meta`

USING(`id_page`) 

*/

$crit = new CDbCriteria();

$crit->select = "title";

$crit->join = "JOIN `page_meta` USING(`id_page`)";

$crit->order = "title ASC";




/*

SELECT *

FROM `page` 

JOIN `page_meta`

USING(`id_page`)  

WHERE `id_page` = (

    SELECT `id_page` FROM `page` 

    WHERE `link` = 'politic-first'

    )

*/

$crit = new CDbCriteria();

$crit->select = "title";

$crit->join = "JOIN `page_meta` USING(`id_page`)";

$crit->condition = "`id_page` = (SELECT `id_page` FROM `page` ";

$crit->condition .= " WHERE `link` = 'politic-first')";

$crit->order = "title ASC";


$dataProvider=new CActiveDataProvider('Page',array(

        'criteria'=>$crit,

        'countCriteria'=>$crit,                    

        'pagination'=>array(

                'pageSize'=>2,

        ),                    

));

}


//далее это вызываете в контроллере как 

$dataProvider=MyModel::getMyProvider()




Это будет уже лучше, нежели сейчас у вас.

Насчет ActiveRecord и бизнес логики. Есть замечательная вещь scopes. Если используете AR, старайтесь логику вносить туда и вызывать так:




$posts=Post::model()->published()->recently()->findAll();



Спросите зачем это? Если вдруг у вас чего то поменяется, вы получите ад в виде бизнес логики в куче разных мест, которую надо менять методом ctrl+c ctrl+v, что в свою очередь ведет к ошибкам.

Если хотите оставить тонкими модели и контроллеры - выносите все в "сервисы". Если интересно как - посмотрите модуль rights, я собственно пока разбирал его, узнал очень много нового и полезного.

про это и спрашивал

ответ получил - спасибо

а вот этот MyModel - он наследуется от AR или нет? любой класс считается моделью если там логика и получение данных из БД?

scopes - это типа область действия: сессии, запрос, приложение?

как в Java? = http://javasource.ru:5050/articles.xhtml?artlink=bean-scopes-in-jsf

разъясните плиз

p.s. плюсик поставил

Не "и", а "или".

Не, это понятие из ActiveRecord

ну так считается класс моделью если в нем есть методы с запросами к БД и возвращающие результат? и если он не наследуется от ActiveRecord

p.s. как в CodeIgniter

Не претендую на истину в последней инстанции, но если класс:

  • не работает с $_GET, $_POST и ежесними, как это делает контролллер.

  • не занимается генерацией и выводом HTML и JS (чему место в вьюхах и хелперах)

то это модель.

В данном случае простой объект, обращающийся в базу и возвращающий результаты является моделью, даже если он не наследуется от ActiveRecord.

Вообще не стоит забывать, что ActiveRecord это один из множества патернов, и MVC это патерн, и AR это не синоним "модели" из MVC. Патерн "Domain Object", к примеру, тоже может выступать в качестве модели. И простой объект, ни от чего не унаследованый, тоже может быть моделью.

спасибо - уразумел