aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Web Development

Laravel Eloquent Relationships: hasMany and belongsTo Guide

Laravel Eloquent relationships let you express the connections between your database tables through readable, elegant PHP objects. The comments on a blog post, the orders belonging to a user, the products in a category… instead of hand-writing JOIN queries to manage these links, you define them with a single method on your Eloquent models. In this article we will cover the two most common relationships — hasMany and belongsTo — with examples, then move on to the other relationship types and to eager loading, the backbone of relational performance.

An overview of relationship types

Eloquent lets you declare related models as methods. In a typical application you will run into these relationships:

  • One-to-one (hasOne / belongsTo): a user has a single profile.
  • One-to-many (hasMany / belongsTo): a post has many comments.
  • Many-to-many (belongsToMany): a post has many tags, and a tag has many posts.
  • Distant and polymorphic relations: more advanced scenarios such as hasManyThrough and morphMany.

This article focuses on the cornerstone one-to-many relationship, because hasMany and its counterpart belongsTo work together.

hasMany: "one record owns many records"

The classic example is a blog: a Post contains many Comment records. On the database side, the comments table holds a post_id column. This foreign key tells which comment belongs to which post.

// app/Models/Post.php
class Post extends Model
{
    public function comments()
    {
        return $this->hasMany(Comment::class);
    }
}

By default, Eloquent assumes the foreign key is the parent model's name (singular) + _id, i.e. post_id. If your column is named differently, you can state it explicitly with the second and third arguments:

return $this->hasMany(Comment::class, 'post_id', 'id');

You can now access a post's comments as if they were a property:

$post = Post::find(1);

foreach ($post->comments as $comment) {
    echo $comment->body;
}

Calling $post->comments without parentheses returns a Collection, whereas $post->comments() returns a query builder. The latter lets you narrow the relationship:

$approved = $post->comments()
    ->where('approved', true)
    ->latest()
    ->get();

belongsTo: the other end of the relationship

belongsTo is the inverse of hasMany. Think from the comment's point of view: each comment belongs to a post. The side that holds the foreign key — the comments table with its post_id column — is always the belongsTo side.

// app/Models/Comment.php
class Comment extends Model
{
    public function post()
    {
        return $this->belongsTo(Post::class);
    }
}

This lets you walk from a comment up to its parent post easily:

$comment = Comment::find(5);
echo $comment->post->title;

Defining both sides is good practice: hasMany on the Post and belongsTo on the Comment. This lets you traverse the relationship in either direction and makes your intent clear to anyone reading the code.

Creating records through a relationship

Eloquent relationships are not just for reading; you can create new records with the foreign key filled in automatically. The save and create methods set post_id for you:

$post = Post::find(1);

$post->comments()->create([
    'body'   => 'Great article, thanks!',
    'author' => 'Alice',
]);

To use create, remember to add the relevant fields to the model's $fillable array. In the other direction, use associate to attach an existing comment to a post:

$comment->post()->associate($post);
$comment->save();

The N+1 problem and eager loading

The most common mistake with relationships is a hidden performance trap: the N+1 query problem. Imagine accessing each post's author inside a loop:

$posts = Post::all(); // 1 query

foreach ($posts as $post) {
    echo $post->author->name; // 1 more query per post
}

With 50 posts that means 1 + 50 = 51 queries. The fix is eager loading: with the with method you load the relationship in advance with a single extra query.

$posts = Post::with('author')->get(); // 2 queries total

foreach ($posts as $post) {
    echo $post->author->name; // no extra query
}

Behind the scenes Eloquent runs a WHERE ... IN (...) query to fetch all authors at once. You can eager load nested and multiple relationships too:

$posts = Post::with(['author', 'comments.user'])->get();

To catch this mistake early during development, you can forbid lazy loading with Model::preventLazyLoading(), or watch the query count with a tool like Laravel Debugbar. If you only need the count of related records, use withCount instead of pulling every row into memory:

$posts = Post::withCount('comments')->get();
echo $posts->first()->comments_count;

Practical tips

  • Always add a database index on foreign key columns; it speeds up relationship queries noticeably.
  • In migrations, use foreignId('post_id')->constrained()->cascadeOnDelete() to create both the index and an integrity constraint.
  • Choose meaningful relationship method names that respect plural/singular consistency: plural for hasMany (comments), singular for belongsTo (post).
  • On listing screens almost always use with; on a single-record detail page, load only what you need.

Frequently Asked Questions

What is the difference between hasMany and belongsTo?

hasMany is defined on the "parent" side of the relationship and represents many child records. belongsTo sits on the "child" side that holds the foreign key and points to a single parent record. They are two directions of the same relationship.

Can I use a foreign key column name different from Eloquent's assumption?

Yes. Pass the foreign key as the second argument and the local key as the third: hasMany(Comment::class, 'article_id', 'id'). Unless told otherwise, Eloquent assumes the singular model name + _id.

Should I always use eager loading?

If you access related data inside a loop, yes — it prevents the N+1 problem. But if you never touch the relationship, do not load it needlessly; that adds extra queries and memory use. Balance it to your needs.

Modeling relationships correctly is the foundation of a fast, maintainable Laravel application. If you need help with Eloquent modeling, N+1 optimization, or a complete Laravel backend build for your project, get in touch with me and let's lay a solid foundation together.

Devamı için