© 2026 Laravel

Quay lại

Laravel Eloquent & Builder: Chinh phục ORM

Ngày đăng 16/02/2026

Eloquent không chỉ là một ORM, nó là một ngôn ngữ biểu diễn dữ liệu.“ Hiểu sâu về Eloquent giúp bạn viết code thanh thoát, ngắn gọn nhưng vẫn đảm bảo hiệu năng tối đa.

#Người mới bắt đầu (Beginner)

Q1: Eloquent Model thực chất là gì?

Trả lời: Là một class implement mẫu thiết kế Active Record. Mỗi instance của Model đại diện cho một hàng trong table, và class Model chứa các method để thao tác với table đó.

Q2: Phân biệt `get()` và `all()`.

Trả lời:

  • all(): Là method static, luôn lấy toàn bộ bản ghi.
  • get(): Là method của Builder, dùng sau khi đã nối chuỗi các điều kiện (ví dụ: where(...)->get()).

#Trung cấp (Intermediate)

Q1: "Magic Methods" đóng vai trò gì trong Eloquent?

Trả lời: Eloquent dùng __get__set để map các thuộc tính của object với các cột trong DB. Khi bạn gọi $user->name, Eloquent sẽ tìm trong mảng $attributes của model thay vì tìm thuộc tính class thật.

Q2: Giải thích cơ chế "Local Scopes" và "Global Scopes".

Trả lời:

  • Local Scope: Method bắt đầu bằng scope, dùng để gom nhóm các điều kiện query hay dùng (ví dụ: scopeActive). Gọi: User::active()->get().
  • Global Scope: Tự động áp dụng điều kiện cho MỌI query của model (ví dụ: SoftDeletes dùng global scope để ẩn các hàng có deleted_at).
Q3: Quan hệ "Has Many Through" dùng khi nào?

Trả lời: Dùng để truy cập quan hệ từ xa qua một model trung gian. Ví dụ: Project -> Environment -> Deployment. Để lấy tất cả deployments của một project, ta dùng hasManyThrough.

#Nâng cao (Advanced)

Q1: Eloquent khởi tạo Query Builder như thế nào? (Internals)

Trả lời: Khi bạn gọi một method static (ví dụ User::where(...)), magic method __callStatic sẽ được kích hoạt. Nó khởi tạo một instance của model, gọi newQuery(), và forward lời gọi tới đối tượng Eloquent\Builder.

Q2: Phân tích hiệu năng của Polymorphic Relationships (Quan hệ đa hình).

Trả lời: Đa hình giúp linh hoạt (1 bảng comment cho cả Post và Video) nhưng gây khó khăn cho việc đánh Index và Referential Integrity (không thể dùng Foreign Key vật lý). Với bảng dữ liệu lớn, đa hình thường chậm hơn so với việc tách bảng riêng.

Q3: Kỹ thuật "Custom Casts" (PHP 8 Attribute style).

Trả lời: Laravel 9+ cho phép định nghĩa các class Cast riêng. Bạn có thể tự động mã hóa/giải mã dữ liệu, hoặc biến đổi JSON phức tạp thành một Value Object ngay khi truy cập thuộc tính model.

#Kiến trúc sư (Architect)

Q1: Khi nào nên kế thừa `Eloquent\Builder` để viết Custom Builder?

Trả lời: Khi model có quá nhiều logic query phức tạp làm “phình” file Model. Việc tách ra Custom Builder giúp tuân thủ nguyên lý Single Responsibility và giúp IDE hỗ trợ gợi ý code tốt hơn.

Q2: Thiết kế hệ thống "Auditing" tự động lưu vết thay đổi model dùng Eloquent Observers.

Trả lời: Tạo một AuditTrait sử dụng bootAuditTrait. Lắng nghe các event updated, created, deleted. So sánh $model->getOriginal() với $model->getAttributes() để tìm ra các cột bị thay đổi và lưu vào bảng audits.

#Câu hỏi Phỏng vấn (Interview Style)

Q: Tại sao không nên dùng `Model::count()` bên trong vòng lặp?

Trả lời: Vì mỗi lần gọi là 1 câu query SELECT COUNT(*) riêng biệt gửi tới DB. Nếu có 1000 vòng lặp, bạn tốn 1000 query. Giải pháp: Lấy data về trước rồi dùng $collection->count() (đếm trên RAM) hoặc dùng withCount() để lấy số lượng ngay trong query gốc.

Q: Làm thế nào để thực hiện query "Subquery select" bằng Eloquent?

Trả lời: Dùng method addSelect() truyền vào một closure hoặc một đối tượng Builder khác. Ví dụ: lấy tên bài viết mới nhất ngay trong query danh sách user.

#Mẹo và thủ thuật

  • toRawSql() (Laravel 10+): Dùng để xem câu query SQL thực tế kèm dữ liệu đã được bind, cực kỳ hữu ích để debug.
  • preventLazyLoading(): Luôn bật trong môi trường Local để ném lỗi ngay lập tức khi bạn quên dùng with().

Bài viết liên quan

Tiếp tục hành trình nâng tầm kiến thức của bạn