2013-07-31 10 views
12

versucht, Fremdschlüssel mit Delete cascade und softDeletes ohne viel Glück zu verwenden.Wie kaskadiert man auf Softdeleten in Laravel4?

Ich habe 2 Tabellen: Benutzer, Ereignisse. Beide Tabellen haben softDeletes.

Benutzer können 0..n Ereignisse haben.
Ereignisse haben eine user_id, als Fremdschlüssel auf Benutzer, so benutzt:

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

Problem ist, wenn ich einen Benutzer löschen, es Soft gelöscht wird, aber die Ereignisse nicht - entweder weich Löschung oder physikalische Streichung.

Mache ich etwas falsch, oder ist das das korrekte eloquente Verhalten?

Zweitens, wenn das das richtige Verhalten ist, wie Löschkaskade am besten zu implementieren? vielleicht überschreiben die delete() methode in meinen modellen wie folgt ...

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

?

Antwort

11

Der Fremdschlüssel der DB wird nichts bewirken, weil Sie den betreffenden Primärschlüssel nicht geändert haben. Nur wenn Sie den Primärschlüssel aktualisieren oder löschen, werden die zugehörigen Zeilen geändert.

Von allem, was ich zu diesem Thema finden kann, ist die Lösung, Eloquent Model Events zu verwenden, auf ein Lösch-Ereignis zu warten, und die zugehörigen Tabellen zu aktualisieren.

Here's one StackOverflow question about it.

Alternativ können Sie „erweitern“, um die delete() Verfahren und beinhalten die Funktionalität als auch direkt. Here's an example.

+0

Cryode, habe ich versucht, die Modelle Events und es funktioniert - aber teilweise. Lassen Sie mich erklären. Die reale Situation ist 3 Tabellen: Benutzer, Ereignisse, Kommentare. Ereignisse haben 0..n Kommentare. Folgend [link] (http://stackoverflow.com/questions/17243637/laravel-4-cascading-soft-deletes), fügte ich Logik in der Methode boot() zu Benutzern und zu Ereignissen hinzu. Jetzt: softDelete Event, erwartet: softDelete Kommentare, Ergebnis: OK; softDelete Benutzer, erwartet: softDelete Ereignisse, Ergebnis: OK, softDelete Kommentare zu diesen Ereignissen, Ergebnis: KO. Es scheint, dass sich die Löschungen nicht über die erste "Ebene" hinaus ausbreiten. – RedSash

+1

Dies ist die Lösung, die ich selbst implementiert habe. Ich zeichne zuerst eine Karte der Beziehungen, die alle meine Modelle miteinander haben und schreibe dann Delete-Methoden, um eloquent in meinen Modellen zu erweitern, die Löschungen kaskadieren sollten. Schließlich, da dies eine leicht aufschiebbare Aufgabe ist, schreibe ich Komponententests, um zu zeigen, dass der Kaskadeneffekt nur das bewirkt, was er bewirkt. Auf diese Weise Benutzer löschen Anrufe UserRecords löschen, die dann UserRecordsMeta löscht aufrufen und so weiter. – carbontwelve

0

Wenn ich richtig verstehe, versuchen Sie, Softdeleten in beiden Tabellen zu kaskadieren?

Ich glaube, dies mit ON UPDATE CASCADE zu tun ist nicht der richtige Ansatz. Ich werde versuchen, zu erklären, warum ...

Um sogar dies zu tun, müssen Sie eine Beziehung von Fremdschlüssel zu Composite-Key erstellen.

dh Sie müssen die (events.user_id und deleted_at) mit (user.id und delete_at) verknüpfen. Du änderst einen, es aktualisiert den anderen.

Zunächst müssen Sie Ihren deleted_at-Spalten eine Standardregel hinzufügen, da Sie keine Verknüpfung mit Nullwerten herstellen können.

Also für beide Tabellen zu Ihrem Migrationen hinzufügen ... $table->softDeletes()->default('0000-00-00 00:00:00');

in Ihre Benutzertabelle mit einem eindeutigen Schlüssel 'id' und 'deleted_at'

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

Dann in den Ereignissen Tabelle einen Fremdschlüssel wie so (Links zu den eindeutigen Schlüssel) erstellen

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'));

Führen Sie dies, sollten Sie jetzt finden Sie, wenn Sie Ihren Benutzer weich löschen, wird es weich löschen seine 'Ereignisse.

Wenn Sie jedoch versuchen, ein Ereignis zu löschen, wird es auf der Fremdschlüsselzurückhaltung fehlschlagen. Warum fragst du?

Nun, was Sie tun, ist das Erstellen einer Parent Child-Beziehung mit ID, deleted_at in beiden Tabellen. Durch das Aktualisieren des übergeordneten Elements wird das untergeordnete Element aktualisiert. Und die Beziehung ist ungebrochen. Wenn Sie jedoch das untergeordnete Element aktualisieren, ist die Beziehung jetzt unterbrochen, sodass das untergeordnete Element als verwaist in der Tabelle verbleibt. Dies schlägt die Fremdschlüsselzurückhaltung fehl.

Sooo eine langatmige Antwort, aber hoffentlich eine gute Erklärung, warum das, was Sie versuchen zu tun, wird nicht funktionieren und sparen Sie eine ganze Menge Zeit, um dies mit ON UPDATE CASCADE zu tun. Treten Sie entweder in die TRIGGERS ein, und TRIGGER Sie eine Funktion, um mit dem, was Sie versuchen, umzugehen oder in Ihrer Anwendung zu handhaben. Persönlich würde ich es mit TRIGGERS tun, so dass die Datenbank ihre eigene Entität bleibt und sich nicht auf irgendetwas verlassen muss, um die Datenintegrität zu bewahren.

delimiter // 

CREATE TRIGGER soft_delete_child AFTER UPDATE ON db.users FÜR JEDE ROW BEGIN IF NEW.deleted_at <> OLD.deleted_at DANN UPDATE Ereignisse SET deleted_at = NEW.deleted_at WHERE events.user_id = NEW.id; ENDE IF; ENDE;

// Trennzeichen;

2

Sie überschätzen dies.

Entweder nur die Ereignisse löschen rechts, bevor Sie die Benutzer löschen:

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

Oder erstellen Sie eine Kundenfunktion im Benutzermodell löschen:

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

Sie könnten auch ein Modell Beobachter und Uhren hinzufügen Für das Lösch- oder Lösch-Ereignis, aber in dem oben erwähnten Szenario wären die beiden vorherigen Methoden eine einfachere Lösung.

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

Verwandte Themen