Eloquent Relationships: The Complete Guide
Eloquent Relationships: Tips & Tricks
Eloquent Relationships: Tips & Tricks
Tip: Always Eager Load in Loops
// Bad: N+1 queries
foreach ($posts as $post) {
echo $post->author->name;
}
// Good: 2 queries total
$posts = Post::with('author')->get();
Gotcha: with() Loads All Related Records
Post::with('comments')->get();
// Loads ALL comments for ALL posts
Use constraints:
Post::with(['comments' => fn($q) => $q->latest()->limit(5)])->get();
Tip: Use exists() Instead of count()
// Bad: loads all records
if ($user->posts->count() > 0) { }
// Good: single EXISTS query
if ($user->posts()->exists()) { }
Tip: whereHas() for Filtering by Relation
Post::whereHas('author', fn($q) => $q->where('active', true))->get();
Gotcha: BelongsToMany Needs a Pivot Table
The table must have both foreign keys. Convention: singular model names alphabetical.
post_user: post_id, user_id
Tip: Access Pivot Data
$user->roles()->attach($roleId, ['expires_at' => now()->addYear()]);
// Access:
$role->pivot->expires_at;
Tip: has() vs whereHas()
Post::has('comments')->get(); // Posts with any comments
Post::whereHas('comments', fn($q) => $q->where('approved', true))->get(); // Posts with approved comments
Gotcha: Polymorphic Relations Can't Use Foreign Keys
No database-level integrity. The related model could be deleted without cleaning up the polymorphic reference.
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: Pivot Data Is Read-Only by Default
Many-to-many pivot columns are read-only unless you define custom pivot models. Use ->withPivot('expires_at') to make them accessible, and newPivot() to make them writable.
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)