Как каскадировать на softdeletes в Laravel4?

Пробовал использовать внешние ключи с удаленным каскадом и softDeletes без большой удачи.

У меня есть 2 таблицы: пользователи, события. Обе таблицы имеют softDeletes.

Пользователи могут иметь 0..n событий.
События имеют user_id, используемые в качестве внешнего ключа для пользователей, например:

$table->foreign('user_id')->references('id')->on('users')->onDelete('CASCADE')->onUpdate('CASCADE');

Проблема в том, что когда я удаляю пользователя, он получает soft-deleted, но его события не имеют - либо мягкое удаление, либо физическое удаление.

Я делаю что-то неправильно или это правильное поведение Красноречивого?

Во-вторых, если это правильное поведение, как наилучшим образом реализовать каскад удаления? возможно, переопределяя метод delete() в моих моделях, подобный этому...

public function delete()
{
  //delete all events...
  __parent::delete()
}

?

Ответ 1

Внешний ключ DB ничего не сделает, потому что вы не изменили первичный ключ. Только если вы обновите или удалите первичный ключ, будут изменены соответствующие строки.

Из всего, что я могу найти по этой теме, решение состоит в том, чтобы использовать Eloquent События модели для прослушивания события удаления и обновления связанных таблиц.

fooobar.com/questions/445963/...

В качестве альтернативы вы можете "расширить" метод delete() и также включить эту функцию напрямую. Вот пример.

Ответ 2

Ты слишком задумываешься об этом.

Либо просто удалите события прямо перед удалением пользователей:

$user->events()->delete();
$user->delete();

Или создать функцию удаления клиента в пользовательской модели:

public function customDelete(){
    $this->events()->delete();
    return $this->delete();
}

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

http://laravel.com/docs/4.2/eloquent#model-observers

Ответ 3

Если я правильно понял, вы пытаетесь каскадировать softdeletes в обеих таблицах?

Я считаю, что делать это с ON UPDATE CASCADE - это не правильный подход. Я попытаюсь объяснить, почему...

Чтобы попытаться сделать это, вам нужно создать отношение внешнего ключа к составному ключу.

т.е. вам нужно связать (events.user_id и deleted_at) с (user.id и delete_at). Вы меняете его, он обновит другой.

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

Итак, добавьте в свои миграции для обеих таблиц... $table->softDeletes()->default('0000-00-00 00:00:00');

Добавьте в свою пользовательскую таблицу уникальный ключ, используя 'id' и 'deleted_at'

Schema::table('users; function($table) { $table->unique(array('id','deleted_at')) });

Затем в таблице событий создайте внешний ключ, подобный этому (ссылки на уникальный ключ)

Schema::table('events; function($table) { $table->foreign(array('user_id','deleted_at'),'events_deleted_at_foreign_key')-> }->references(array('id','deleted_at'))->on('users')->onUpdate('CASCADE'));

Запустите это, теперь вы должны найти, если вы мягко удалите своего пользователя, он будет мягко удалять свои "события".

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

Хорошо, что вы делаете, это создание отношений родительского ребенка с использованием id, deleted_at в обеих таблицах. Обновление родителя, обновление ребенка. И отношения не прерываются. Однако, если вы обновите дочерний элемент, теперь связь будет нарушена, в результате чего ребенок станет сиротой в таблице. Это не сдерживает внешний ключ.

Соуй длинный ответ, но, надеюсь, хорошее объяснение, почему то, что вы пытаетесь сделать, не сработает и сэкономит вам много времени, пытаясь сделать это с помощью UPDATE CASCADE. Либо заходите в TRIGGERS, и TRIGGER - это функция для обработки того, что вы пытаетесь сделать, или обрабатываете ее в своем приложении. Лично я делаю это с помощью TRIGGERS, поэтому база данных остается ее собственной сущностью и не должна полагаться ни на что, чтобы сохранить целостность данных.

delimiter //

СОЗДАТЬ ТРИГГЕР soft_delete_child ПОСЛЕ ОБНОВЛЕНИЯ НА db.users ДЛЯ КАЖДОЙ РУКИ НАЧАТЬ   IF NEW.deleted_at < > OLD.deleted_at THEN       События UPDATE SET deleted_at = NEW.deleted_at WHERE events.user_id = NEW.id;   END IF; END;

// разделитель;