ZEND Framework - Problema com a tabela de dados Tabela Recursive Cascading Excluir
Pergunta
Minha situação pode ser um pouco anormal, mas tenho chaves estrangeiras definidas no meu banco de dados MySQL, ao mesmo tempo em que aplica integridade referencial no Zend_Db_Table
Aulas. As tabelas usam o mecanismo de armazenamento Innodb.
Ao excluir um registro, a estrutura Zend identificará adequadamente crianças imediatas através do $_referenceMap
no modelo da tabela e exclua -os. No entanto, se houver algum filho da criança imediata, estou recebendo um erro do banco de dados sobre como violar a integridade referencial dessa chave estrangeira: SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails
. Parece que o Zend_Db_Table_Abstract
Não aplica integridade referencial de maneira recursiva.
Mais alguém encontrou isso? É um Zend Framework Bug? Soluções alternativas? Conserta?
ATUALIZAR
Quase uma semana depois e não tenho respostas a essa pergunta. Estou pensando que vou ter que estender o Zend_Db_Table_Row_Abstract
Classifique -me para conseguir isso.
Solução
Acabei estendendo o Zend_Db_Table_Abstract
classe para conseguir isso. o _cascadeDelete
Função pública faz uma chamada para o adaptador de banco de dados delete
função. Eu fiz alterações para que o delete
função de Zend_Db_Table_Row_Abstract
é chamado em vez disso. Isso torna as deleções recordes recursivas.
ATUALIZAR: Eu adicionei código para quando o excluir está definido como self::SET_NULL
.
Aqui está minha versão modificada de _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;
}