setIntegrityCheck в Zend Выбирает с объединениями - PullRequest
13 голосов
/ 25 февраля 2012

Я смотрел на некоторые вопросы , которые спрашивают, как сделать объединения в запросах Zend Framework, но ответ всегда что-то вроде "просто сделай 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.

Ответы [ 2 ]

23 голосов
/ 25 февраля 2012

Вызов 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 и не требуют записи или удаления строка. для этого конкретного случая пользователя можно получить строку или набор строк путем передачи значения FALSE в setIntegrityCheck () . Результирующий строка или набор строк будут возвращены как «заблокированная» строка (то есть save () , delete () и любые методы установки поля будут вызывать исключение).

См. Также: Объединения «один ко многим» с Zend_Db_Table_Select

9 голосов
/ 25 февраля 2012

Хорошо, я провел какое-то исследование, и не совсем верно , что вы должны позвонить 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, без проблем.

...