Laravel'in güçlü orm kütüphanesi olan Eloquent, veritabanı operasyonları ile ilgili pek çok faydalı işleve sahiptir. Bugün, bu işlevlerin en önemlilerinden biri olan ve uygulama hızını ciddi derecede artıran eager loading'den bahsedeceğim.

Eloquent ile aralarında ilişki bulunan modellere ait veriler, varsayılan olarak lazy loaded şeklinde yüklenir. Yani ilişkili modele ait verilere erişmeye çalışana kadar aslında bu veriler yüklenmez. Dolayısıyla bu verilere erişildiği anda Eloquent arka planda yeni bir sorgu daha çalıştırır ve ilişkili modele ait verileri yükler. Bu da N+1 olarak bilinen ve performansı olumsuz yönde etkileyen probleme sebep olur. 

Eager Loading kavramı, işte bu N+1 problemini çözmek için ortaya atılmıştır. Eloquent ile eager loading işlemi aşağıdaki iki yöntem ile gerçekleştirilebilir;

  • with()
  • load()

Her iki Eloquent yöntemi de aynı sonucu döndürür. Bu iki yöntem arasındaki temel fark, with() yöntemi, ilişkili modellerin tüm verilerini yüklerken, load() yöntemi, ana modele ait veriler alındıktan sonra, duruma göre ilişkili modellerin tüm verilerinin elde edilmesine yardımcı olur.

Örnek olarak Laravel'in resmi dökümantasyonunda yer alan Book ve Author modellerini inceleyelim;

Elimizde kitaplar ve yazarların bulunduğu 2 adet tablomuz ve dolayısıyla 2 adet de modelimiz olsun. Kitapların bulunduğu Book modelini aşağıdaki gibi oluşturalım;

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    /**
     * Get the author that wrote the book.
     */
    public function author()
    {
        return $this->belongsTo('App\Author');
    }
}


Şimdi de kitapları, yazarları ile birlikte almaya çalışalım;

$books = App\Book::all();

foreach ($books as $book) {
    echo $book->author->name;
}


Yukarıdaki döngü, tablodaki tüm kitapları almak için 1, daha sonra her kitabın yazarını almak için başka bir sorgu daha yürütür. Sonuç olarak eğer 10 kitabımız varsa, orijinal kitap için 1 ve her bir kitabın yazarını almak için ek 10 sorgu yürütülecektir. Probleme N+1 denmesinin sebebi de budur.

Eager Loading yöntemi ile bu işlemi yalnızca 2 sorgu ile gerçekleştirmek mümkündür. Sorgulama yaparken hangi ilişkiye ait verilerin yükleneceğini with() yöntemi ile belirtebiliriz.

$books = App\Book::with('author')->get();

foreach ($books as $book) {
    echo $book->author->name;
}


Yukarıdaki kod yalnızca 2 adet sorgu çalıştıracaktır. İlk sorgu, books tablosundaki tüm kitapları, ikinci sorgu ise authors tablosundaki yazarları in() yöntemi ile alır.

select * from books

select * from authors where id in (1, 2, 3, 4, 5, ...)


Birden Fazla İlişki için Eager Loading Kullanımı

Bazı durumlarda tek bir işlemle, ana model ile ilişkili olan birden fazla modelden veri almamız gerekebilir. Bunun için yapılması gereken tek şey, with() yöntemine ilişkili modelleri bir array içerisinde vermektir.

$books = App\Book::with(['author', 'publisher'])->get();


Yukarıdaki örnekte kitaplar, yazarları ve yayınevleri ile birlikte alınmaktadır.


Eager Loading ile Kısıtlamalar

Bazı durumlarda eager loading ile yüklemek istediğimiz verilerin belirleyeceğimiz bazı koşullara uymasını isteyebiliriz. Bunun için istediğimiz koşulu barındıran bir fonksiyonu, model anahtarına değer olarak tanımlayabiliriz.

$users = App\Book::with(['author' => function ($query) {
    $query->where('country', 'Turkey');
}])->get();


Yukarıdaki örnekte, kitaplar ve yalnızca ülkesi Türkiye olan yazarlar yüklenecektir.


Lazy Eager Loading

Birbiri ile ilişkili olan modellere ait verileri bir defada almak için with() yöntemini kullandık. Ancak bazı durumlarda, ilişkili modele ait verilere sadece belirli koşullar sağlandığında erişmek isteyebiliriz. Bunun için load() yöntemini kullanabiliriz;

$books = App\Book::all();

if ($someCondition) {
    $books->load('author', 'publisher');
}


Yukarıdaki örnekte, önce tüm kitaplar alınıyor ve ardından $someCondition olarak belirlenen koşul sağlanıyorsa, Author ve Publisher modellerindeki ilişkili veriler alınıyor.