SetIntegrityCheck в Zend Выбор с помощью соединений
Я смотрел несколько questions, которые спрашивали, как выполнять объединения в запросах Zend Framework, но ответ всегда что-то вроде "просто do setIntegrityCheck(FALSE)
".
Мой вопрос: зачем мне это нужно?
Мне кажется, что отключение "проверки целостности" не является надлежащим способом выполнения этой работы. В моем конкретном случае я использую базу данных MySQL с некоторыми таблицами InnoDB с внешними ключами, например, например:
CREATE TABLE IF NOT EXISTS `tableA`
(
`id` CHAR(6),
`name` VARCHAR(255),
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `tableB`
(
`tableA_id` CHAR(6),
`somefield` VARCHAR(255),
PRIMARY KEY (`tableA_id`)
) ENGINE=InnoDB;
ALTER TABLE `tableB` ADD FOREIGN KEY fk1 (`tableA_id`) REFERENCES `tableA` (`id`);
(это очень упрощенная версия моей БД)
И мой код запроса выглядит так:
$table = new Zend_Db_Table('tableB');
$select = $table->select(TRUE)
->join(array('a' => 'tableA'), 'tableB.tableA_id = a.id');
$result = $table->fetchAll($select);
Это дает мне исключение "Выбрать запрос не может присоединиться к другой таблице", если я не добавлю setIntegrity(FALSE)
к моему $select
.
Ответы
Ответ 1
Хорошо, я провел некоторое исследование, и не совсем верно, что вы должны называть setIntegrityCheck(FALSE)
для объединения.
Соответствующий код в классе Zend_Db_Select
(т.е. единственное место, где можно найти очень последнее слово для этого аргумента), содержит этот код:
if ($this->_integrityCheck !== false) {
foreach ($fields as $columnEntry) {
list($table, $column) = $columnEntry;
// Check each column to ensure it only references the primary table
if ($column) {
if (!isset($from[$table]) || $from[$table]['tableName'] != $primary) {
require_once 'Zend/Db/Table/Select/Exception.php';
throw new Zend_Db_Table_Select_Exception('Select query cannot join with another table');
}
}
}
}
Итак, на самом деле, он проверяет, принадлежат ли все выбранные поля в запросе к "первичной таблице". Запрос не обязательно должен возвращать все поля во вовлеченных таблицах.
Возвращаясь к примеру в моем вопросе, получается, что этот работает:
$table = new Zend_Db_Table('tableB');
$select = $table->select(TRUE)
->join(array('a' => 'tableA'), 'tableB.tableA_id = a.id', NULL); // <-- notice the third parameter here
$result = $table->fetchAll($select);
Этот новый запрос возвращает только поля из tableB
, но вы можете добавить условия where
в любую из таблиц, как это обычно бывает с SQL, без проблем.
Ответ 2
Вызов setIntegrityCheck(false)
- это правильный способ сделать соединение; если вы используете Zend_Db_Table
и Zend_Db_Table_Select
, вы не можете присоединиться, если вы не отключите проверку целостности.
Проверка целостности выполняется только для того, чтобы убедиться, что запрос НЕ использует несколько таблиц, и когда он на месте, гарантирует, что объекты Zend_Db_Table_Row
могут быть удалены или изменены, а затем сохранены, поскольку данные строки являются исключительными для одного таблицу и не представляет собой сочетание данных из разных таблиц.
Чтобы указать, что вы ХОТИТЕ использовать несколько таблиц, укажите setIntegrityCheck(false)
, чтобы Zend Framework знала, что это намеренно. В результате вы получаете заблокированную строку, которая не может называть save()
или delete()
on.
Вот цитата из справочного руководства по Zend_Db_Table - Расширенное использование (перейдите к примеру 27.
Zend_Db_Table_Select используется в основном для ограничения и проверки чтобы он мог применять критерии для юридического запроса SELECT
. Однако могут быть определенные случаи, когда вам требуется гибкость Zend_Db_Table_Row и не требует перезаписываемых или удаляемых ряд. для этого конкретного случая пользователя можно получить строку или rowset, передав значение FALSE
в setIntegrityCheck(). Результирующий строка или набор строк будут возвращены как "заблокированная" строка (это означает save(), delete(), и любые методы настройки полей выдадут исключение).
См. также: Входы "один ко многим" с Zend_Db_Table_Select