Laravel İle İlişkisel Veritabanı İçin Eloquent İlişki Kurma Nasıl Yapılır?

Laravel İle İlişkisel Veritabanı İçin Eloquent İlişki Kurma Nasıl Yapılır?
Laravel İle İlişkisel Veritabanı İçin Eloquent İlişki Kurma Nasıl Yapılır?

Ön Hazırlık ve Gereksinimler

Laravel ile çalışmaya başlamadan önce, sisteminizde PHP 8.2 veya üzeri bir sürümün ve Composer paket yöneticisinin kurulu olduğundan emin olmalısınız. Ayrıca, veritabanı bağlantılarınızın .env dosyasında doğru yapılandırıldığını kontrol edin.

  • Laravel 11 veya 12 sürümü yüklü bir proje ortamı.
  • MySQL veya PostgreSQL veritabanı sürücüsü.
  • Temel düzeyde SQL ve PHP nesne yönelimli programlama bilgisi.

Adım Adım Bire-Bir (One-to-One) İlişki Kurma

Bire-bir ilişki, bir tablodaki tek bir kaydın başka bir tablodaki tek bir kayıtla eşleştiği durumdur. Örneğin, bir "Kullanıcı"nın (User) sadece bir "Profil"i (Profile) olabilir.

Öncelikle User modelinde profil ilişkisini tanımlayalım:

// app/Models/User.php
public function profile()
{
    return $this->hasOne(Profile::class);
}

Bu kod, User modelinin Profile modeline sahip olduğunu belirtir. Karşı tarafta, yani Profile modelinde ise bu ilişkinin kime ait olduğunu belirtmemiz gerekir:

// app/Models/Profile.php
public function user()
{
    return $this->belongsTo(User::class);
}

Bu ilişkiyi test etmek için bir kullanıcıya ait profil verisine şu şekilde erişebilirsiniz: $user->profile->bio;. Laravel burada user_id sütununu otomatik olarak arayacaktır.

Bire-Çok (One-to-Many) İlişki Yapılandırması

Bire-çok ilişki, en sık kullanılan ilişki türüdür. Bir "Yazar"ın (Author) birden fazla "Kitap"ı (Post) olabilir. Bu durumda hasMany ve belongsTo yöntemlerini kullanırız.

Yazar modelinde kitapları tanımlayalım:

// app/Models/Author.php
public function posts()
{
    return $this->hasMany(Post::class);
}

Kitap modelinde ise yazar ile olan bağı kuralım:

// app/Models/Post.php
public function author()
{
    return $this->belongsTo(Author::class);
}

Bu yapılandırma sayesinde, bir yazarın tüm yazılarını $author->posts şeklinde bir koleksiyon olarak çekebilir, her bir yazının yazarını ise $post->author üzerinden kolayca alabilirsiniz.

Çoka-Çok (Many-to-Many) İlişki ve Pivot Tablolar

Çoka-çok ilişki, birden fazla kaydın birden fazla başka kayıtla eşleştiği durumlardır. Örneğin, "Öğrenciler" ve "Dersler". Burada bir ara tabloya (pivot table) ihtiyacımız vardır.

Laravel'de belongsToMany metodunu kullanarak bu ilişkiyi tanımlarız:

// app/Models/Student.php
public function courses()
{
    return $this->belongsToMany(Course::class, 'course_student', 'student_id', 'course_id');
}

Eğer pivot tablonuzda ek veriler (örneğin kayıt tarihi) tutuyorsanız, ilişkiyi tanımlarken withPivot metodunu kullanmanız gerekir:

// app/Models/Student.php
public function courses()
{
    return $this->belongsToMany(Course::class)->withPivot('enrolled_at');
}

Güvenlik Uyarısı: İlişkisel veritabanı sorguları yaparken, kullanıcıdan gelen verileri asla doğrudan sorguya dahil etmeyin. Laravel'in Eloquent yapısı, SQL injection saldırılarına karşı otomatik koruma sağlar; ancak ham sorgular (raw queries) yazarken her zaman parametre bağlama (parameter binding) yöntemini kullanın.

İlişkisel Veritabanı Yöntemlerinin Karşılaştırılması

Aşağıdaki tablo, Laravel Eloquent ilişkilerinin kullanım senaryolarını özetlemektedir:

İlişki Türü Eloquent Metodu Kullanım Senaryosu
Bire-Bir hasOne / belongsTo Kullanıcı - Profil
Bire-Çok hasMany / belongsTo Yazar - Yazılar
Çoka-Çok belongsToMany Öğrenci - Dersler
Polimorfik morphTo / morphMany Yorumlar (Hem yazılara hem videolara)

Yaygın Hatalar ve Debug İpuçları

İlişkileri kurarken en sık karşılaşılan hata, veritabanı sütun isimlerinin Laravel'in beklediği standartlara (örneğin user_id) uymamasıdır. Eğer özel bir sütun ismi kullanıyorsanız, ilişki metodunda bu ismi belirtmelisiniz.

Hata ayıklama için toSql() metodunu kullanabilirsiniz:

// Sorguyu çalıştırmadan SQL çıktısını görmek için
dd($user->posts()->toSql());

Bu yöntem, Laravel'in arka planda oluşturduğu SQL sorgusunu görmenizi sağlar ve olası yanlış birleşimleri (join) tespit etmenize yardımcı olur.

Sıkça Sorulan Sorular

Eloquent ilişkilerinde performans sorunu yaşar mıyım?

Evet, "N+1 sorgu problemi" ile karşılaşabilirsiniz. Bunu engellemek için with() metodunu kullanarak "Eager Loading" (istekli yükleme) yapmalısınız.

Pivot tablolarda veri nasıl güncellenir?

Pivot tablodaki verileri güncellemek için updateExistingPivot metodunu kullanabilirsiniz. Bu, ilişkiyi silmeden sadece ara tablodaki sütun değerini değiştirir.

Polimorfik ilişki nedir?

Polimorfik ilişki, bir modelin birden fazla farklı modelle tek bir ilişki üzerinden bağlanabilmesidir. Örneğin, "Yorumlar" tablosu hem "Yazılar"a hem de "Ürünler"e ait olabilir.

İlişkilerde silme işlemi nasıl yönetilir?

Laravel'de onDelete('cascade') kullanarak, ana kayıt silindiğinde ona bağlı olan ilişkili kayıtların da otomatik silinmesini sağlayabilirsiniz.

İlişki kurarken neden hata alıyorum?

Genellikle model isimlerinin veya namespace'lerin yanlış tanımlanmasından kaynaklanır. Modellerinizin App\Models dizininde olduğundan ve isimlerin veritabanı tablosuyla uyumlu olduğundan emin olun.

Eloquent İlişkilerinde Eager Loading ile Performans Optimizasyonu

Eloquent ilişkilerini kullanırken en sık karşılaşılan performans sorunu "N+1" problemidir. Laravel, varsayılan olarak ilişkili verileri "Lazy Loading" (tembel yükleme) yöntemiyle getirir. Yani, bir döngü içerisinde her bir model için ayrı bir veritabanı sorgusu çalıştırılır. Bu durum, binlerce kaydın olduğu tablolarda sunucunuzu ciddi şekilde yavaşlatır.

Bu sorunu çözmek için Eager Loading (istekli yükleme) yöntemini kullanmalısınız. with metodunu kullanarak ilişkili verileri tek bir sorguda, IN operatörü ile çekebilirsiniz.

// N+1 Problemi Yaratan Kod (Kötü Uygulama)
$users = User::all();
foreach ($users as $user) {
    echo $user->profile->bio; // Her döngüde veritabanına sorgu gider
}

// Eager Loading ile Optimize Edilmiş Kod (İyi Uygulama)
$users = User::with('profile')->get();
foreach ($users as $user) {
    echo $user->profile->bio; // Veriler zaten bellekte, sorgu çalışmaz
}

Ayrıca, sadece ihtiyacınız olan sütunları çekerek bellek kullanımını daha da optimize edebilirsiniz:

$users = User::with('profile:id,user_id,bio')->get();

İlişkisel Verilerde Test Yazımı ve Veri Bütünlüğü

İlişkisel bir yapıda model testleri yazarken, veritabanı bütünlüğünü korumak için RefreshDatabase trait'ini kullanmak en sağlıklı yöntemdir. Bu, her testten önce veritabanının temizlenmesini ve testlerin izole çalışmasını sağlar.

Aşağıdaki örnek, bir Post modelinin User ile olan ilişkisini test etmek için kullanılan bir birim testidir:

namespace Tests\Unit;

use Tests\TestCase;
use App\Models\User;
use App\Models\Post;
use Illuminate\Foundation\Testing\RefreshDatabase;

class RelationshipTest extends TestCase
{
    use RefreshDatabase;

    public function test_post_belongs_to_a_user()
    {
        $user = User::factory()->create();
        $post = Post::factory()->create(['user_id' => $user->id]);

        $this->assertInstanceOf(User::class, $post->user);
        $this->assertEquals($user->id, $post->user->id);
    }
}

Bu test yapısı, veritabanı şemanızda bir değişiklik yaptığınızda ilişkilerin hala doğru çalışıp çalışmadığını anında doğrulamanıza yardımcı olur. Özellikle foreign key kısıtlamalarını test ederken, geçersiz bir kullanıcı ID'si ile post oluşturmaya çalıştığınızda Laravel'in veya veritabanının hata fırlatıp fırlatmadığını kontrol etmek, uygulamanızın hata toleransını artıracaktır.

İleri Düzey İpucu: İlişkilerde Varsayılan Sıralama

Bazen ilişkili verileri her zaman belirli bir sırada (örneğin en yeni tarihli) çekmek isteyebilirsiniz. Bunu model içerisinde ilişki tanımlarken kolayca yapabilirsiniz:

public function comments()
{
    return $this->hasMany(Comment::class)->orderBy('created_at', 'desc');
}

Bu yöntem, uygulamanın farklı yerlerinde tekrar tekrar orderBy kullanma zorunluluğunu ortadan kaldırarak kodunuzu temiz tutmanızı sağlar.

Sonuç

Laravel ile Eloquent ilişkileri kurmak, veritabanı yönetimini nesne yönelimli bir yapıya dönüştürerek kodunuzu daha okunabilir ve sürdürülebilir kılar. Bu rehberde öğrendiğiniz yöntemleri kullanarak, projelerinizde veriler arası güçlü bağlar oluşturabilirsiniz. Bir sonraki adım olarak, Eloquent'in gelişmiş özelliklerinden biri olan "Polimorfik İlişkiler" konusunu inceleyerek daha dinamik veri yapıları tasarlamayı deneyebilirsiniz.

Yasal Sorumluluk Reddi: Bu makalede paylaşılan kod örnekleri eğitim amaçlıdır. Yazılım geliştirme süreçlerinde veritabanı güvenliği, yedekleme ve sunucu yapılandırması gibi konularda profesyonel standartlara uymak geliştiricinin sorumluluğundadır. Bu bilgiler herhangi bir yatırım veya hukuk tavsiyesi içermez.

Bu yazıya tepkinizi paylaşın:
Zeynep Arslan

Kullanıcı deneyimi odaklı içerik üretiminde uzmanlaşmış bir editörüm. Özellikle DIY projeleri ve teknik rehberler üzerine detaylı içerikler üretiyorum.

Yorumlar (0)

Yorum Yaz