Eloquent Soft Deletes
Eloquent Soft Deletes: Tips & Tricks
Eloquent Soft Deletes: Tips & Tricks
Tip: Unique Constraints Break with Soft Deletes
A soft-deleted record still exists in the database. If you have a unique constraint on slug, you can't create a new record with the same slug.
Fix: Use a composite unique index:
$table->unique(['slug', 'deleted_at']);
Gotcha: withTrashed() Affects Relationships Too
$user->posts()->withTrashed()->get();
Without withTrashed(), soft-deleted related models are excluded.
Tip: Restore with Relations
$post->restore();
$post->comments()->withTrashed()->each(fn($c) => $c->restore());
Gotcha: forceDelete() is Permanent
$post->forceDelete(); // Gone forever
No undo. Be careful.
Tip: Check if Soft Deleted
$post->trashed(); // true if soft deleted
$post->restore(); // Undelete
Tip: Auto-Delete Relations on Soft Delete
protected static function booted(): void
{
static::deleting(function ($post) {
if (! $post->isForceDeleting()) {
$post->comments()->delete(); // Soft deletes comments too
}
});
}
Gotcha: onlyTrashed() Returns Only Deleted
Post::onlyTrashed()->get(); // Only soft-deleted posts
Post::withTrashed()->get(); // All posts including deleted
Tip: Schedule Cleanup of Old Soft Deletes
$schedule->call(function () {
Post::onlyTrashed()->where('deleted_at', '<', now()->subDays(90))->forceDelete();
})->daily();
Tip: Use cursor() for Memory-Neutral Iteration
When exporting 100K rows, get() loads everything into memory. cursor() uses yield and keeps memory flat regardless of row count. Perfect for artisan commands.
Tip: whereHas() vs load() — Two Different Things
whereHas() filters the parent query by relationship existence. load() eager-loads relationships AFTER the query. Mixing them up is a common source of logic bugs.
Gotcha: withCount() Adds a Subquery
withCount('comments') runs a correlated subquery on every row. On large tables, this can be slower than a separate query. Profile before relying on it.
Senior Insight
Eloquent is Laravel's most controversial feature — developers either love its convenience or hate its magic. My take after years of using both Eloquent and raw SQL: Eloquent is excellent for 80% of queries and wrong for the other 20%. The skill is knowing which is which. If a query involves more than three joins, window functions, or complex subqueries, reach for the Query Builder or raw SQL. Eloquent's beauty is in its simplicity for CRUD; fighting it for complex queries helps no one.
Source: Laravel Docs (https://laravel.com/docs/eloquent), Laravel News (https://laravel-news.com/), Freek.dev (https://freek.dev/tags/eloquent)