Zend Framework - Проблема с рекурсивным каскадным удалением таблиц базы данных - PullRequest
1 голос
/ 11 июня 2010

Моя ситуация может быть немного ненормальной, но у меня есть внешние ключи, определенные в моей базе данных MySQL, при одновременном обеспечении ссылочной целостности в классах Zend_Db_Table. В таблицах используется механизм хранения InnoDB.

При удалении записи Zend Framework будет правильно определять непосредственных потомков через $_referenceMap в табличной модели и удалять их. Однако, если есть дочерние элементы непосредственного дочернего элемента, я получаю сообщение об ошибке из базы данных о нарушении ссылочной целостности этого внешнего ключа: SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails. Кажется, что Zend_Db_Table_Abstract не обеспечивает рекурсивную ссылочную целостность.

Кто-нибудь еще сталкивался с этим? Это ошибка Zend Framework ? Обходные? Исправления


UPDATE

Почти неделю спустя, и у меня нет ответов на этот вопрос. Я думаю, мне придется самому расширить класс Zend_Db_Table_Row_Abstract, чтобы достичь этого.

1 Ответ

0 голосов
/ 22 июня 2010

В итоге я расширил класс Zend_Db_Table_Abstract для достижения этой цели.Открытая функция _cascadeDelete вызывает функцию адаптера базы данных delete.Я внес изменения, так что вместо этого вызывается функция delete из Zend_Db_Table_Row_Abstract.Это делает удаление записей рекурсивным.

ОБНОВЛЕНИЕ: Я добавил код, когда при удалении установлено значение self::SET_NULL.

Вот моя измененная версия _cascadeDelete:

/**
 * Called by parent table's class during delete() method.
 *
 * @param  string $parentTableClassname
 * @param  array  $primaryKey
 * @return int    Number of affected rows
 */
public function _cascadeDelete($parentTableClassname, array $primaryKey)
{
    $this->_setupMetadata();
    $rowsAffected = 0;
    foreach ($this->_getReferenceMapNormalized() as $map) {
        if ($map[self::REF_TABLE_CLASS] == $parentTableClassname && isset($map[self::ON_DELETE])) {
            switch ($map[self::ON_DELETE]) {
                case self::CASCADE:
                    $select = $this->select();
                    for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) {
                        $col = $this->_db->foldCase($map[self::COLUMNS][$i]);
                        $refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]);
                        $type = $this->_metadata[$col]['DATA_TYPE'];
                        $select->where($this->_db->quoteIdentifier($col, true) . ' = ?',
                            $primaryKey[$refCol], $type);
                    }
                    $rows = $this->fetchAll($select);
                    $rowsAffected += count($rows);
                    foreach ($rows as $row) {
                        $row->delete();
                    }
                    break;
                case self::SET_NULL: {
                    $update = array();
                    $where = array();
                    for ($i = 0; $i < count($map[self::COLUMNS]); ++$i) {
                        $col = $this->_db->foldCase($map[self::COLUMNS][$i]);
                        $refCol = $this->_db->foldCase($map[self::REF_COLUMNS][$i]);
                        $type = $this->_metadata[$col]['DATA_TYPE'];
                        $update[$col] = null;
                        $where[] = $this->_db->quoteInto(
                            $this->_db->quoteIdentifier($col, true) . ' = ?',
                            $primaryKey[$refCol], $type);
                    }
                    $rowsAffected += $this->update($update, $where);
                    break;
                }
                default:
                    // no action
                    break;
            }
        }
    }
    return $rowsAffected;
}
...