Eloquent: Relationships trong Laravel (Phần 4)

Tram Ho

Vậy là qua 3 phần viết về Relationships trong Laravel, khá dài rồi nhỉ. Phần này sẽ là phần cuối cùng về chủ để này, mình chia sẻ về Eager Loading và cách insert, update các quan hệ nhé.
Phần 3 các bạn xem ở đây nhé.

4. Eager Loading

Nhắc đến Eager Loading các bạn phải nhớ ngay đến vấn đề N + 1 query nhé. Vấn đề này xảy ra khi bạn gọi relationship của model như 1 thuộc tính, khi đó dữ liệu quan hệ là “lazy loaded”. Nói dễ hiểu hơn là các relationship không thực sự load ra trước khi bạn gọi đến nó. Khi gọi relationship sẽ gặp thực hiện N + 1 câu truy vấn. Nếu dùng eager loading, vấn đề này sẽ được giảm bớt.

Ví dụ: Model Book có quan hệ với Author

Sau đó lấy tất cả sách và in ra tên tác giả:

Dòng lệnh đầu tiên sẽ thực hiện 1 truy vấn lấy ra tất cả book. Giả sử có N quyển sách. Vòng lặp sẽ lặp N lần, mỗi lần thực hiện 1 truy vấn lấy ra tên tác giả của sách. Vậy là N + 1 truy vấn rồi. ?

Nếu dùng eager loading, bạn chỉ mất 2 truy vấn thôi ?. Ta sẽ dùng phương thức with(). Tham số truyền vào là tên của relationship muốn lấy ra cùng model.

Khi đó, relationship sẽ được load ra cùng với model. 2 truy vấn được thực hiện:

Muốn lấy nhiều relationship cùng 1 câu lệnh, truyền mảng relationship vài hàm with().

Eager loading lồng nhau

Ví dụ: lấy ra tác giả (author) của sách và cách liên hệ (contacts) của tác giả đó, ta dùng dấu ‘.’ nhé.

Eager loading lồng nhau trong quan hệ đa hình

Ví dụ ta có model ActivityFeed:

Giả sử 3 model Event, Photo, Post có thể tạo ra ActivityFeed. Model Event belongsTo Calendar, Photo belongsTo Tag, Post belongsTo Author. Để truy vấn ActivityFeed và lấy ra parentable cùng với các quan hệ belongsTo tương ứng, ta dùng morphWith().

Eager loading với các cột

Đôi khi mình không muốn lấy ra tất cả các trường của 1 model thì có thể chọn các trường cụ thể. Chú ý là nên lấy ra id và các khóa ngoại khác nhé.

Ví dụ mình chỉ lấy cột id và name của author.

Eager loading mặc định

Nếu bạn muốn mỗi khi truy vấn model đều dùng Eager loading thì bạn có thể thêm thuộc tính $with vào model.

Có mặc định thì cũng có cách để bỏ đi những mặc định này nhé. Nếu bạn không muốn load thêm author thì dùng phương thức without() nhé.

Thêm ràng buộc cho Eager Loading

Nâng cao hơn 1 chút, ta sẽ thêm ràng buộc khi dùng Eager Loading. Trong 1 số trường hợp, các relationship có thêm điều kiện.

Ví dụ: chỉ load ra những poststitle chứa chữ first.

Note: Không dùng các phương thức limittake trong trường hợp này.

Lazy Eager Loading

Lazy Eager Loading khác với Lazy Loading ở bên trên nhé. Phương pháp này dùng khi bạn muốn load 1 relationship sau khi đã truy vấn model cha, khi nào dùng thì mới load ra. Tất nhiên nó vẫn tối ưu câu truy vấn nhé. Thay vì dùng with() ta sẽ dùng load().

Tham số truyền vào là các relationship muốn lấy ra.

Tương tự bên trên, ta có thể thêm ràng buộc truy vấn cho Lazy Eager Loading.

loadMissing()
Vì truy vấn lấy relationship thực hiện sau khi đã lấy ra model cha nên bạn có thể load relationship khi nó chưa được load trước đó.

Lazy Eager Loading lồng nhau & morphTo

Sử dụng ví dụ của phần Eager Loading, thay vì dùng withMorth() ta dùng loadMorph().

Tổng kết

Mình xin kết thúc Relationships trong Laravel ở đây. Hy vọng sau khi đọc, các bạn có thể hiểu và áp dụng được relationship vào project của mình 1 cách thật sự tự tin và chính xác.

Tài liệu tham khảo

https://laravel.com/docs/6.x/eloquent-relationships#constraining-eager-loads

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo