Laravel Tutorial

Bài 33: Eloquent ORM relationship trong Laravel – Phần 3

Phần này chúng ta cùng nhau tìm hiểu về eager loading trong Eloquent ORM relationship, liên quan đến query, performace trong việc query đến Database trong Laravel nên nó rất quan trọng

1. Định nghĩa eager loading

Mặc định, eloquent ORM relationship sẽ chỉ thực hiện query relation khi chúng ta truy vấn đến nó như một thuộc tính (nó sẽ truy vấn nếu như property này được gọi lần đầu tiên, các lần gọi tiếp theo nó sẽ lấy dữ liệu đã truy vấn trước đó). Điều này sẽ làm cho code của bạn sẽ bị dính lỗi “N + 1” query nếu bạn sử dụng chúng trong vòng lặp. 

Ví dụ: Mình có một model Book và khai báo relation với Author model (1 cuốn sách thuộc một tác giả)

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

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

Lấy ra tất cả book và thông tin tác giả của sách đó theo cách thông thường

use App\Models\Book;

$books = Book::all();

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

Giả sử bạn có 10 cuốn sách thì đoạn code trên sẽ thực thi 11 câu query. Trong đó một câu query lấy ra tất cả 10 cuốn sách và 10 câu query để lấy ra từng author tương ứng với từng cuốn sách

Đối với trường hợp trên, nếu như bạn sử dụng eager loading, thì nó chỉ thực thi duy nhất 2 câu query. Một câu lấy ra 10 cuốn sách sau đó và một câu query để lấy ra 10 author tương ứng với 10 cuốn sách đó (sử dụng WHERE IN rồi dùng code để mapping vào với author)

2. Sử dụng eager loading

Để sử dụng eager loading trong Eloquent các bạn sử dụng phương thức with

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


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

Lúc này SQL query sẽ có dạng như sau:

select * from books

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

Bạn cũng có thể sử dụng phương thức with để eager load nhiều relation cho một lần gọi, bằng cách truyền vào một array chứa các relation name

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

Bạn cũng có thể eager load lồng nhiều cấp động bằng cách sử dụng ký tự “.

Ví dụ: Book model có relation Author và Author lại có relation đến Contact, bạn có thể eager loading cả author và contact tương ứng như sau:

$books = Book::with('author.contact')->get();

Mặc định Laravel sẽ lấy tất cả các column data trong relation (SELECT *), nhưng nếu cần bạn có thể chỉ định những column nào cần lấy ra

Ví dụ: Chỉ lấy ra column “id” và “name” của author

$books = Book::with('author:id,name')->get();

* Nếu như bạn muốn thiết lập eager loading luôn luôn được load cho model nào thì bạn có thể setting các relation vào thuộc tính $with trong model

Ví dụ: Luôn sử dụng eager loading với relation ‘author‘ trong model Book

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    /**
    * The relationships that should always be loaded.
    *
    * @var array
    */

    protected $with = ['author'];
    
    /**
    * Get the author that wrote the book.
    */
    
    public function author()
    {
        return $this->belongsTo(Author::class);
    }
}

Nếu bạn muốn loại bỏ eager loading cho một query nào đó trong model đã thiết lập eager loading mặc định, bạn có thể sử dụng phương thức without

Ví dụ: Loại bỏ eager loading trong query đối với setting Book trong Ví dụ trên

$books = Book::without('author')->get();

Nếu như bạn muốn sử dụng thêm điều kiện để query trong relation với eager loading mode, bạn có thể sử dụng giá trị của mảng trong phương thức with là closure

use App\Models\User;

$users = User::with(['posts' => function ($query) {
    $query->where('title', 'like', '%code%');
}])->get();

Leave a Comment