Есть ли способ заставить saveAll () удалять посторонние объекты? - PullRequest
4 голосов
/ 03 ноября 2010

Мой хост-объект имеет множество объектов-опций, связанных с ним. В форме редактирования пользователи могут (де) выбирать параметры и сохранять этот новый набор ассоциаций. Это реализовано с помощью saveAll () для опубликованных данных. В результате

  • объект хоста (основной) обновлен,
  • опция (связанные) объекты, которые включены как в предыдущую, так и в новую ассоциацию, обновляются, и
  • Создаются объекты опций, которые не были включены в предыдущую связь, но включены в новую.

Но чего не происходит, это

  • что объекты опций, которые были включены в предыдущую связь, но не в новую, удаляются.

Вопрос: Может ли saveAll () сделать то же самое, и как должна выглядеть структура данных для достижения этого эффекта?

Информация, связанная с данной:

Мой код для обработки формы редактирования на самом деле более сложный (поэтому я не цитировал его здесь), но это приводит к структуре данных, как описано в книге:

( [Host] => ( ... host object fields ... ),
  [Option] => ( [0] => ( ... first option object fields ... ),
                ...
                [n] => ( ... nth option object fields ... )
              )
)

Теперь, если исходный хост имел связанную опцию, которая не включена в массив 0..n, saveAll () не обнаружит это и не удалит этот связанный объект.

Не уверен, что это актуально, но я использую CakePHP 1.3.

Ответы [ 5 ]

2 голосов
/ 28 октября 2011

Вы можете гарантировать, что все будет выполнено атомарно, если вы вручную заключите все в транзакцию.

Это можно сделать с помощью методов begin(), rollback() и commit() источника данных:

$this->Main->begin();

if ( !$this->Main->save(...) ) {
  $this->Main->rollback();
  return false;
}

// Perform saves in related models...
if ( !$this->Main->MainRelatedModel->save(...) ) {
  $this->Main->rollback();
  return false;
}

// Perform deletes in extraneous records...
if ( !$this->Main->MainRelatedModel->delete(...) ) {
  $this->Main->rollback();
  return false;
}

// Everything went well, commit and close the transaction
$this->Main->commit();

Основным недостатком здесь является то, что транзакции не могут быть вложенными, следовательно, вы не можете использовать saveAll().Вы должны сохранить / удалить все шаг за шагом, вместо того, чтобы делать это за один вызов.

2 голосов
/ 03 ноября 2010

Не совсем элегантное решение, но у меня работает.

if ($this->Main->saveAll($this->data))
{
    $this->Main->query(sprintf(
        'DELETE '
        . 'FROM extraneous '
        . 'WHERE main_id = \'%s\' AND modified < (SELECT modified FROM main WHERE id = \'%1$s\')'
        , mysql_real_escape_string($this->Main->id)
    ));
}

Обратите внимание, что в ваших таблицах должно быть измененное поле .

1 голос
/ 07 ноября 2013

Ища это, я заметил, что все еще нет встроенного в CakePHP решения. Для этого я добавил следующий код в мою модель:

private $oldBarIds = array();
public function beforeSave($options = array() {
    parent::beforeSave($options);

    $this->oldBarIds = array();
    if ($this->id && $this->exists() && isset($this->data['Bar'])) {
        $oldBars = $this->Bar->find('all', array(
            'fields' => array('id'),
            'conditions' => array(
                'Bar.foo_id' => $this->id
            )
        ));
        $this->oldBarIds = Hash::extract($oldBars, '{n}.id');
    }
}

Проверяет, существует ли Bar в сохраняемых данных. Если это произойдет, он получит текущие идентификаторы текущих, установив их на $this->oldBarIds. Затем при успешном сохранении следует удалить старые:

public function afterSave($created, $options = array()) {
    parent::afterSave($created, $options);

    if (!$created && $this->oldBarIds) {
        $this->Bar->deleteAll(array(
            'Bar' => $this->oldBarIds
        ));
    }
}

Таким образом, удаление обрабатывается моделью и происходит только при успешном сохранении. Должен быть в состоянии добавить это к поведению, может когда-нибудь сделать это.

1 голос
/ 03 ноября 2010

saveAll() не удалит ничего из вашей базы данных.

Полагаю, лучший способ - удалить параметры, связанные с текущим хостом, перед сохранением, а затем добавить их. Однако, если вам необходимо обновить те, которые уже существуют (не так ли?) По какой-то причине (например, параметры связаны с некоторыми другими моделями), я думаю, вы можете попытаться написать фрагмент кода, который удалит невыбранные параметры.

0 голосов
/ 03 ноября 2010

HABTM удаляет все связанные записи, а затем воссоздает то, что нужно.* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * '*' 'Вы можете вручную удалить соответствующие записи непосредственно перед сохранением.Опасность, однако, заключается в том, что при сбое сохранения вы теряете предыдущее состояние.

Я бы выбрал вариант решения GJ и удалил их после успешного сохранения, а вместо этого сделал циклнад массивом избыточных идентификаторов и используйте метод Cake Model-> del ().Таким образом вы сохраняете все встроенные средства обработки ошибок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...