Прекратить использование Containable.Это действительно генерирует слишком много запросов.Используйте joins
синтаксис.Взгляните на этот вопрос и на кулинарную книгу статья .
ОБНОВЛЕНИЕ
Присоединение к столам
В SQL вы можете комбинировать связанные таблицы, используя оператор JOIN
.Это позволяет выполнять сложный поиск по нескольким таблицам (т. Е. Искать сообщения с несколькими тегами).
В CakePHP некоторые ассоциации (belongsTo
и hasOne
) выполняют автоматическое объединение для извлечения данных, поэтому вы можете выполнить командузапросы для извлечения моделей на основе данных в связанной.
Но это не относится к ассоциациям hasMany
и hasAndBelongsToMany
.Здесь на помощь приходят форсированные соединения.Вам нужно только определить необходимые объединения, чтобы объединить таблицы и получить желаемые результаты для вашего запроса.
Помните, что для этого нужно установить рекурсию на -1
.Т.е.: $this->Channel->recursive = -1;
Для принудительного объединения таблиц необходимо использовать «современный» синтаксис для Model::find()
, добавив ключ ‘joins’
к массиву $options
.Например:
$options['joins'] = array(
array('table' => 'channels',
'alias' => 'Channel',
'type' => 'LEFT',
'conditions' => array(
'Channel.id = Item.channel_id',
)
)
);
$Item->find('all', $options);
Обратите внимание, что массивы ‘join’
не имеют ключа.
В приведенном выше примере модель с именем Item остается присоединенной к таблице каналов.Вы можете создать псевдоним таблицы с именем модели, чтобы полученные данные соответствовали структуре данных CakePHP.
Ключами, определяющими объединение, являются следующие:
table
:Таблица для объединения. alias
: псевдоним таблицы.Лучшая ставка - название модели, связанной с таблицей. type
: тип объединения: внутреннее, левое или правое. conditions
: условия выполненияобъединение.
С помощью объединений вы можете добавлять условия на основе связанных полей модели:
$options['joins'] = array(
array('table' => 'channels',
'alias' => 'Channel',
'type' => 'LEFT',
'conditions' => array(
'Channel.id = Item.channel_id',
)
)
);
$options['conditions'] = array(
'Channel.private' => 1
);
$privateItems = $Item->find('all', $options);
В hasBelongsToMany можно выполнить несколько объединений, если необходимо:
ПредположимКнига hasAndBelongsToMany
Тег ассоциации.Это отношение использует таблицу books_tags в качестве таблицы объединения, поэтому вам необходимо присоединить таблицу books к таблице books_tags, и это с таблицей тегов:
$options['joins'] = array(
array('table' => 'books_tags',
'alias' => 'BooksTag',
'type' => 'inner',
'conditions' => array(
'Books.id = BooksTag.books_id'
)
),
array('table' => 'tags',
'alias' => 'Tag',
'type' => 'inner',
'conditions' => array(
'BooksTag.tag_id = Tag.id'
)
)
);
$options['conditions'] = array(
'Tag.tag' => 'Novel'
);
$books = $Book->find('all', $options);
Использование объединений с поведением Containable может привести к некоторым ошибкам SQL(дубликаты таблиц), поэтому вам нужно использовать метод соединений в качестве альтернативы для Containable, если ваша главная цель - выполнять поиск на основе связанных данных.Containable лучше всего подходит для ограничения количества связанных данных, передаваемых оператором find.