2013-07-31 20 views
12

試圖用刪除級聯和softDeletes使用外鍵沒有多少運氣。如何在Laravel4中對softdeletes進行級聯?

我有2個表:用戶,事件。兩個表都有softDeletes。

用戶可以有0..n個事件。
事件有USER_ID,用作外鍵的用戶來說,這樣的:

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

問題是,當我刪除一個用戶,它變得軟刪除,但其活動不 - 無論是軟刪除或物理刪除。

我做錯了什麼,還是這是正確的雄辯行爲?其次,如果這是正確的行爲,如何最好地實現刪除級聯?也許重寫我的模型中的delete()方法,像這樣...

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

回答

11

數據庫的外鍵不會執行任何操作,因爲您沒有更改相關主鍵。只有當您更新或刪除主鍵時,纔會修改相關的行。

從我能找到的有關此主題的所有信息中,解決方案是使用Eloquent的Model Events來偵聽刪除事件並更新相關表。

Here's one StackOverflow question about it.

備選地,可以在「擴展」的delete()方法和包括的功能直接爲好。 Here's an example.

+0

Cryode,我試過模型事件,它的工作原理 - 但部分。讓我解釋。真實情況是3個表格:用戶,事件,評論。事件有0..n條評論。在[link](http://stackoverflow.com/questions/17243637/laravel-4-cascading-soft-deletes)之後,我在boot()方法中向用戶和事件添加了邏輯。 現在:softDelete事件,預期:softDelete評論,結果:OK; softDelete用戶,預期:softDelete事件,結果:OK,softDelete對這些事件的評論,結果:KO。看來刪除不會超出第一個「級別」。 – RedSash

+1

這是我自己實現的解決方案。我首先繪製了我所有模型之間關係的映射,然後編寫刪除方法以在我的模型中擴展雄辯,從而使級聯刪除。最後,因爲這是一個容易豎起來的任務,所以我編寫了單元測試來表明級聯效果隻影響它的效果。這樣用戶刪除呼叫UserRecords刪除後再調用UserRecordsMeta刪除等等。 – carbontwelve

0

如果我理解正確,您試圖在兩個表中級聯softdeletes?

我相信這樣做與ON更新CASCADE不是正確的方法。我試圖解釋爲什麼...

甚至要嘗試這樣做,您需要創建外鍵與複合鍵的關係。

即你需要將(events.user_id和deleted_at)鏈接到(user.id和delete_at)。你改變一個,它會更新另一個。

首先,您需要爲您的deleted_at列添加默認規則,因爲您無法鏈接到空值。

所以添加到您的遷移兩個表... $table->softDeletes()->default('0000-00-00 00:00:00');

添加到您的用戶表中的唯一鍵使用「身份證」和「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創建父子關係。更新父母,將更新孩子。這種關係是不間斷的。但是,如果您更新孩子,現在關係中斷,將孩子留在表中作爲孤兒。這失敗了外鍵約束。

Sooo一個漫長的回答,但希望能夠很好地解釋爲什麼你想要做的事情不會奏效,併爲你節省大量的時間試圖用ON UPDATE CASCADE來做到這一點。要麼進入TRIGGERS,要麼觸發一個函數來處理你想要做的事情,或者在你的應用程序中處理它。就我個人而言,我會用TRIGGERS來做,所以數據庫仍然是它自己的實體,不必依靠任何東西來保持數據的完整性。

delimiter // 

CREATE TRIGGER soft_delete_child UPDATE ON FOR EACH ROW db.users AFTER BEGIN IF NEW.deleted_at <> OLD.deleted_at THEN UPDATE SET事件= deleted_at WHERE NEW.deleted_at = events.user_id NEW.id; END IF; END;

// 定界符;

2

你正在推翻這一點。

要麼只是刪除事件,你刪除權限的用戶才:

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

或者創建一個客戶用戶模型中刪除功能:

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

你也可以添加一個模型觀察者和手錶對於刪除或刪除事件,但在上面提到的場景中,前兩種方法是更簡單的解決方案。

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

相關問題