Laravel Eloquent Relationships: İlişki Türleri Rehberi
Laravel Eloquent relationships, veritabanındaki tablolar arasındaki bağlantıları model metotlarıyla ifade eder. Bir yazının yorumları, bir siparişin kullanıcısı veya bir ürünün kategorileri gibi bağlantılar doğru tanımlandığında sorgular okunabilir olur; yanlış kullanıldığında ise N+1 sorguları, eksik foreign key değerleri ve beklenmeyen veri kayıpları ortaya çıkar.
Bu rehberde hasOne, hasMany, belongsTo, belongsToMany ve polymorphic ilişkileri gerçek kod örnekleriyle kuracağız. Ayrıca eager loading, pivot verileri, ilişki sorguları ve testleri ele alacağız. Sürümünüze ait ayrıntılar için resmî Laravel Eloquent ilişkileri belgesini kontrol edin.
Eloquent relationship nasıl tanımlanır?
İlişkiler model sınıfında dönüş tipi belirtilen metotlar olarak tanımlanır. Laravel varsayılan olarak model ve metot adlarından foreign key adını tahmin eder. Örneğin Post modelinin yorumları comments.post_id sütununa bağlanır:
use Illuminate\Database\Eloquent\Relations\HasMany;
class Post extends Model
{
public function comments(): HasMany
{
return $this->hasMany(Comment::class);
}
}

Ters yönde Comment modelinin hangi yazıya ait olduğunu belongsTo ile belirtin:
use Illuminate\Database\Eloquent\Relations\BelongsTo;
public function post(): BelongsTo
{
return $this->belongsTo(Post::class);
}
Veritabanınız Laravel adlandırma kurallarını izlemiyorsa foreign key ve yerel anahtarı metot parametrelerinde açıkça verin. Ancak yeni tablolarda standart post_id biçimi, gereksiz yapılandırmayı azaltır.
Dynamic property ile ilişki metodu farkı
$post->comments ilişkili koleksiyonu yükler veya önceden yüklendiyse bellekteki sonucu döndürür. $post->comments() ise ilişki sorgusunu verir; buna where, latest veya count ekleyebilirsiniz:
$approvedComments = $post->comments()
->where('is_approved', true)
->latest()
->get();
One to one ve one to many ilişkileri
Bir kullanıcının tek profili varsa hasOne, bir yazının birçok yorumu varsa hasMany kullanılır. İlişkili modeli doğrudan foreign key atamak yerine ilişki üzerinden oluşturmak, anahtarın doğru yazılmasını sağlar:
$profile = $user->profile()->create([
'bio' => $validated['bio'],
]);
$comment = $post->comments()->create([
'body' => $validated['body'],
'user_id' => $request->user()->id,
]);
Controller’a yalnızca doğrulanmış veriyi geçirin. Form Request ve güvenli veri seçimi için Laravel validation rehberini uygulayın.
İlişkili kaydın varlığını sorgulama
has ve whereHas, ilişkili kayıt varlığına göre ana modeli filtreler:
$posts = Post::query()
->whereHas('comments', function ($query) {
$query->where('is_approved', true);
})
->withCount('comments')
->get();
Yalnızca sayıya ihtiyacınız varsa tüm yorum koleksiyonunu yüklemek yerine withCount kullanın. Toplam, ortalama veya en büyük değer için ilgili withSum, withAvg ve benzeri aggregate metotları değerlendirin.
Many to many ve pivot tablo kullanımı

Bir yazı birçok etikete, bir etiket de birçok yazıya aitse belongsToMany kullanılır. Laravel varsayılan pivot tablo adını model adlarının alfabetik sırasından üretir. Özel bir adınız varsa ikinci parametrede belirtin:
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class)
->withPivot('assigned_by')
->withTimestamps();
}
Pivot verisini $user->roles->first()->pivot->assigned_by biçiminde okuyabilirsiniz. Kayıt yönetiminde temel metotların farkı şöyledir:
attach($id)ilişki ekler.detach($id)ilişkiyi kaldırır.sync([$ids])listeyi verilen kimliklerle eşitler; listede olmayan bağlantıları kaldırır.syncWithoutDetaching([$ids])mevcut ilişkileri silmeden yenilerini ekler.
sync kullanmadan önce kaldırılacak ilişkilerin gerçekten istenmediğini doğrulayın. Yetki kontrolünü yalnızca arayüzdeki seçime bırakmayın; gönderilen tüm kimlikleri Laravel güvenlik kontrol listesine göre doğrulayın.
Polymorphic relationship ne zaman kullanılır?
Yorum, görsel veya etiket gibi bir model birden fazla model türüne bağlanacaksa polymorphic ilişki tekrar eden tabloları azaltabilir. Örneğin hem Post hem Video yorum alıyorsa comments tablosunda commentable_id ve commentable_type bulunur:
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;
// Post model
public function comments(): MorphMany
{
return $this->morphMany(Comment::class, 'commentable');
}
// Comment model
public function commentable(): MorphTo
{
return $this->morphTo();
}
Veritabanında tam sınıf adlarını saklamak, namespace değişikliğinde eski veriyi etkileyebilir. Morph map ile post veya video gibi kararlı tür adları tanımlamak daha sürdürülebilir olabilir. Sadece olası bir gelecekte kullanılır düşüncesiyle polymorphic yapı kurmayın; basit foreign key daha anlaşılırsa onu seçin.
N+1 sorgusu ve eager loading çözümü

Aşağıdaki kod önce yazıları, ardından her yazının yazarı için ayrı sorgu çalıştırabilir:
$posts = Post::latest()->get();
foreach ($posts as $post) {
echo $post->author->name;
}
İlişkiyi önceden yükleyerek sorgu sayısını sabitleyin:
$posts = Post::query()
->with([
'author:id,name',
'tags:id,name',
])
->latest()
->paginate(20);
Seçilen sütunlar arasında ilişkinin kurulması için gereken anahtarları unutmayın. Mevcut bir koleksiyonda ilişki gerektiğinde load(), yalnızca yüklenmemişse loadMissing() kullanılabilir. Geliştirme ortamında lazy loading’i engellemek, gizli N+1 problemlerini daha erken görünür kılar.
Blade döngüsüne geçmeden önce ilişkileri controller’da yükleyin; görünüm katmanını düzenlemek için Laravel Blade template rehberine bakın.
İlişkili kayıtları güvenli güncelleme
Foreign key atamalarında ilişki yardımcıları niyeti açık eder:
$comment->post()->associate($post);
$comment->save();
$comment->post()->dissociate();
$comment->save();
Birden fazla tabloyu birlikte güncelliyorsanız transaction kullanın. Örneğin sipariş oluşturulup satırlar eklenirken ikinci adım başarısız olursa yarım sipariş bırakılmamalıdır. Queue’ya gönderilecek işlerin commit edilmeden çalışması da ayrıca ele alınmalıdır; ağır arka plan işleri için Laravel Queue rehberini inceleyin.
Eloquent relationship testleri
Factory relationship yardımcılarıyla gerçek foreign key düzenini test edin:
public function test_post_has_comments(): void
{
$post = Post::factory()
->has(Comment::factory()->count(3))
->create();
$this->assertCount(3, $post->comments);
$this->assertDatabaseHas('comments', [
'post_id' => $post->id,
]);
}
Many-to-many testinde pivot tablosundaki iki foreign key’i ve ek pivot alanlarını doğrulayın. Tutarlı test verisi üretmek için Laravel Seeder ve Factory rehberini kullanın.
İlişki kontrol listesi
- İlişki yönü doğru mu:
hasManyvebelongsTodoğru modellerde mi? - Migration foreign key, index ve silme davranışı iş kuralına uyuyor mu?
- Döngü öncesinde gereken ilişkiler eager load ediliyor mu?
- Sadece sayı gerekiyorsa koleksiyon yerine
withCountkullanılıyor mu? syncçağrısının kaldıracağı pivot kayıtları biliniyor mu?- Polymorphic tür adları namespace değişiminden korunuyor mu?
- İlişki oluşturma ve silme davranışı test ediliyor mu?
Sıkça Sorulan Sorular
hasMany ile belongsTo arasındaki fark nedir?
hasMany ana modelden çok sayıdaki alt kayda gider. belongsTo ise foreign key taşıyan alt modelden sahibine döner.
Eloquent ilişkisinde foreign key nasıl değiştirilir?
İlişki metoduna ikinci parametre olarak özel foreign key verilir. Gerekirse üçüncü parametreyle ana modeldeki yerel veya owner key de belirtilebilir.
N+1 sorgusu nasıl anlaşılır?
Bir liste döngüsünde her satır için aynı türde ek sorgu çalışıyorsa N+1 ihtimali yüksektir. Query log veya profil aracıyla sorgu sayısını ölçün ve gereken ilişkileri with() ile yükleyin.
attach ile sync arasındaki fark nedir?
attach yeni pivot bağlantısı ekler. sync ise mevcut bağlantıları verilen listeyle eşitler ve listede olmayanları kaldırabilir.
Polymorphic ilişki her zaman daha iyi midir?
Hayır. Aynı alt model gerçekten birden fazla model türüne bağlanıyorsa yararlıdır. Tek türe ait veri için normal foreign key genellikle daha basit ve daha kolay denetlenir.
Sonuç
Laravel Eloquent relationships yalnızca model metotları değildir; veritabanı şeması, sorgu maliyeti ve veri bütünlüğüyle birlikte tasarlanmalıdır. Doğru ilişki yönünü seçin, foreign key ve silme davranışını migration’da netleştirin, liste sorgularında eager loading kullanın ve pivot güncellemelerini test edin. Böylece okunabilir model kodu elde ederken performans ve veri güvenliğini de korursunuz.




