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