DELETE A CHILD ROW WHILE DELETING THE PARENT
Feb 16, 2024 Copy Link
You should be aware that the problem always lies in removing the parent app, record, or whatever thing that has children, not vice versa, and to solve this problem you should remove the child before removing the parent. It's not related to Programming
only but, it's a global problem that exists in all Tech.
fields especially the Databases
so, let me explain how to deal with this scenario in Laravel
Let's consider that every user has only one car. The database schema is gonna be:
Schema::create('cars', function (Blueprint $table) {
$table->id();
$table->string('type');
$table->unsignedBigInteger('number_plate')->unique();
$table->unsignedBigInteger('price');
$table->foreignId('user_id')->constrained();
$table->timestamps();
});
When you start to migrate and seed your database and then try to remove the user with a car you will get an Integrity constraint violation exception. To resolve that trouble, you should configure something to remove the child before the parent is removed so, Laravel gives us a nice chainable `cascadeOnDelete`
method that you can use after the `constrained`
method:
Schema::create('cars', function (Blueprint $table) {
...
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->timestamps();
});
Laravel provides other approaches to the previous line.
After the previous update when you re-delete the user again, it will be successfully deleted with a child car 💣
FYI, there are many other ways to do so, we will explain them but get everything back first then let's make changes to the parent model which is the `User.php`
class to fade away this exception:
// \App\Models\User.php
public static function boot()
{
parent::boot();
static::deleting(function ($user) {
$user->car()->delete();
});
}
Also, you can write the same previous code in the `AppServiceProvider.php`
class:
// \App\Providers\AppServiceProvider.php
use App\Models\User;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
User::deleting(fn ($user) => $user->car()->delete());
}
It's IMPORTANT to use the Database Transaction with such a previous scenario.
Previously, we have used almost identical two ways to remove the car that the user had while he was deleting and these ways will succeed in doing so but, these fail to remove children when we try to remove a dozen parents:
use App\Models\User;
User::whereIn('id', [11, 12, 15])->delete();
Removing a dozen users always succeeds in the cascading delete without any additional configurations.
The previous code will fire the exception that we know, so we will make a bit of change:
use App\Models\User;
User::whereIn('id', [11, 12, 15])->get()->each->delete();
FINALLY, we have achieved our target goal for a second time! 🤸♂️
To dive into the previous
`each`
property you need to read more about Higher Order Messages.