Laravel İle Eloquent İlişkileri Kullanarak Veritabanı Sorgusu Nasıl Yapılır?

Ön Hazırlık ve Gereksinimler

Bu eğitimden en yüksek verimi alabilmek için bilgisayarınızda Laravel 11 veya 12 sürümünün yüklü olması gerekmektedir. Ayrıca, veritabanı bağlantılarınızın .env dosyasında doğru yapılandırıldığından emin olmalısınız. Çalışma ortamınızda PHP 8.2+ sürümü ve Composer paket yöneticisi yüklü olmalıdır.

  • Laravel framework kurulu bir proje.
  • MySQL veya PostgreSQL veritabanı bağlantısı.
  • İlişkili tabloları oluşturmak için migration dosyaları.

Eloquent İlişkilerini Tanımlama

Eloquent ilişkilerini kullanmadan önce, modellerinizde bu ilişkileri tanımlamanız gerekir. Örneğin, bir kullanıcının birden fazla siparişi olabilir (One-to-Many). Bu ilişkiyi tanımlamak için User modeline bir metod eklemelisiniz.

// app/Models/User.php
public function orders()
{
    return $this->hasMany(Order::class);
}

Bu kod bloğu, User modelinin Order modeli ile "bire-çok" ilişkisini kurar. Laravel, varsayılan olarak user_id sütununu arayacaktır. Eğer farklı bir sütun kullanıyorsanız, metodun ikinci parametresinde bunu belirtebilirsiniz.

Eager Loading ile Performanslı Sorgular

Veritabanı sorgularında en sık karşılaşılan hata "N+1" sorunudur. Bu sorun, ilişkili verileri her döngüde ayrı bir sorgu ile çekmeye çalıştığınızda oluşur. Laravel'de with() metodunu kullanarak ilişkili verileri tek bir sorgu ile çekebilirsiniz.

// Controller içerisinde kullanım
$users = User::with('orders')->get();

foreach ($users as $user) {
    echo $user->orders->count();
}

with('orders') metodu, tüm kullanıcıların siparişlerini tek bir SQL sorgusu ile getirir. Bu, uygulamanızın veritabanı yükünü ciddi oranda azaltır ve sayfa yüklenme hızını artırır.

İlişkili Veriler Üzerinden Filtreleme Yapmak

Bazen sadece belirli kriterlere sahip ilişkili verileri çekmek istersiniz. Örneğin, "en az bir siparişi olan kullanıcıları" listelemek için has() metodunu kullanabilirsiniz.

// En az bir siparişi olan kullanıcıları getir
$activeUsers = User::has('orders')->get();

// Sipariş tutarı 500 TL'den büyük olan kullanıcıları getir
$highValueUsers = User::whereHas('orders', function ($query) {
    $query->where('total_price', '>', 500);
})->get();

whereHas() metodu, ilişkili tablo üzerinde bir kısıtlama yapmanıza olanak tanır. Bu yöntem, veritabanında EXISTS sorgusu çalıştırarak oldukça verimli bir filtreleme sağlar.

İlişki Türleri ve Kullanım Alanları

Laravel'de farklı senaryolar için çeşitli ilişki türleri mevcuttur. İhtiyacınıza göre doğru ilişkiyi seçmek, sorgularınızın başarısını doğrudan etkiler.

İlişki Türü Açıklama Kullanım Senaryosu
hasOne Bire-Bir ilişki Kullanıcı ve Profil bilgisi
hasMany Bire-Çok ilişki Kullanıcı ve Siparişler
belongsToMany Çoka-Çok ilişki Ürünler ve Kategoriler
morphTo Polimorfik ilişki Yorumlar (Ürün veya Blog için)

İlişkili Verileri Güncelleme ve Ekleme

Eloquent, ilişkili verileri kaydederken de büyük kolaylık sağlar. Bir kullanıcıya yeni bir sipariş eklemek için save() veya create() metodlarını kullanabilirsiniz.

$user = User::find(1);

$user->orders()->create([
    'order_number' => 'ORD-12345',
    'total_price' => 250.00,
    'status' => 'pending'
]);

Bu örnekte, user_id alanı Laravel tarafından otomatik olarak atanır. Bu, manuel veri girişi hatalarını önler ve veritabanı bütünlüğünü korur.

Güvenlik Uyarısı: Kullanıcıdan gelen verileri doğrudan veritabanına kaydetmeyin. Her zaman $fillable dizisini kullanarak model üzerinde hangi alanların doldurulabileceğini kısıtlayın ve gelen verileri validate() metodu ile doğrulayın.

Sıkça Sorulan Sorular

N+1 sorunu nedir ve nasıl engellenir?

N+1 sorunu, ilişkili verilerin döngü içinde her seferinde ayrı bir sorgu ile çekilmesidir. with() metodu ile Eager Loading kullanarak bu sorunu engelleyebilirsiniz.

belongsTo ve hasOne arasındaki fark nedir?

hasOne, tablonun dış anahtarı (foreign key) karşı tarafta olduğunda kullanılır. belongsTo ise dış anahtarın mevcut tabloda olduğu durumda kullanılır.

İlişkili verileri nasıl sıralayabilirim?

Eloquent sorgularında with(['orders' => function($query) { $query->orderBy('created_at', 'desc'); }]) yapısını kullanarak ilişkili verileri sıralayabilirsiniz.

Çoka-çok ilişkide pivot tabloyu nasıl sorgularım?

belongsToMany ilişkisi tanımlandıktan sonra withPivot('sütun_adı') metodunu kullanarak ara tablodaki verilere erişebilirsiniz.

Eloquent sorgularını nasıl debug edebilirim?

Sorgunun sonuna toSql() ekleyerek üretilen SQL kodunu görebilir veya DB::enableQueryLog() ile tüm sorguları inceleyebilirsiniz.

İleri Düzey İpucu: İlişkilerde "Lazy Eager Loading" Kullanımı

Bazen, bir model örneğini zaten yüklemiş olabilirsiniz ve ilişkili verileri yalnızca belirli bir koşul gerçekleştiğinde çekmeniz gerekebilir. Bu durumda load() yöntemi devreye girer. Bu yöntem, halihazırda bellekte olan modeller için ilişkileri "sonradan" yüklemenize olanak tanır.

$users = User::all();

if ($needsProfile) {
    $users->load('profile');
}

Bu yaklaşım, özellikle koşullu mantıkların yoğun olduğu servis katmanlarında gereksiz veritabanı sorgularını engellemek için mükemmel bir yöntemdir. Ayrıca, loadMissing() yöntemini kullanarak, ilişkinin zaten yüklenip yüklenmediğini kontrol edebilir ve sadece yüklenmemiş olanları sorguya dahil edebilirsiniz.

Eloquent İlişkilerinde Performans Optimizasyonu: "Chunking" ve "Lazy"

Büyük veri setleriyle çalışırken, tüm ilişkili kayıtları tek bir sorguda çekmek bellek (RAM) sınırlarını zorlayabilir. Eloquent, büyük koleksiyonları yönetmek için chunk() ve lazy() yöntemlerini sunar. Özellikle ilişkili verilerle işlem yaparken lazy() kullanımı, veritabanı bağlantısını açık tutarak verileri "yield" eder ve bellek kullanımını minimuma indirir.

// 1000'erli gruplar halinde ilişkili yorumları işleme
User::with('comments')->lazy()->each(function ($user) {
    foreach ($user->comments as $comment) {
        // Her yorum üzerinde işlem yap
        echo $comment->body;
    }
});

Bu yöntem, özellikle binlerce kullanıcı ve milyonlarca yorumun olduğu sistemlerde, sunucunun "Out of Memory" hatası almasını engeller. lazy() yöntemi, cursor() yönteminin bir sarmalayıcısıdır ve ilişkilerle birlikte kullanıldığında oldukça verimli sonuçlar verir.

İlişkili Verilerde "Count" Sorgularını Optimize Etmek

Bir liste sayfasında her kullanıcının yorum sayısını göstermek istediğinizi varsayalım. Eğer $user->comments->count() kullanırsanız, bu her döngüde yeni bir sorgu çalıştırır (N+1 sorunu). Bunun yerine withCount() yöntemini kullanmalısınız:

// Sorgu anında yorum sayısını ekler
$users = User::withCount('comments')->get();

foreach ($users as $user) {
    echo $user->comments_count; // Ek sorgu yapmadan veriyi yazdırır
}

Bu yöntem, Laravel'in arka planda bir LEFT JOIN veya alt sorgu çalıştırarak veriyi tek seferde almasını sağlar. withCount() ayrıca belirli koşullara göre sayım yapmanıza da izin verir:

$users = User::withCount(['comments' => function ($query) {
    $query->where('is_approved', true);
}])->get();

Bu teknik, özellikle admin panelleri veya raporlama ekranları gibi yoğun veri gösterimi yapılan yerlerde uygulama hızını %80'e varan oranlarda artırabilir.

Sonuç

Laravel ile Eloquent ilişkilerini kullanmak, veritabanı işlemlerini daha temiz, güvenli ve performanslı hale getirir. Bu rehberde öğrendiğiniz with(), has() ve whereHas() gibi yöntemler, profesyonel bir Laravel geliştiricisi olma yolunda atacağınız en önemli adımlardır. Bir sonraki adım olarak, "Polimorfik İlişkiler" konusunu inceleyerek daha esnek veritabanı tasarımları yapmayı öğrenebilirsiniz.

Sorumluluk Reddi: Bu makaledeki kod örnekleri eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce veritabanı yedeklerinizin alındığından ve gerekli güvenlik testlerinin yapıldığından emin olun. Yazılım güvenliği, sürekli güncellenen bir süreçtir; Laravel'in resmi dokümantasyonunu takip etmeyi ihmal etmeyin.

Bu yazıya tepkinizi paylaşın:
Mert Özdemir

Teknoloji ve dijital dünyadaki karmaşık süreçleri adım adım rehberlerle sadeleştiriyorum. Kullanıcıların dijital araçlardan en yüksek verimi alması için anlaşılır ve öğretici içerikler yazıyorum.

Yorumlar (0)

Yorum Yaz