Eloquent firstOrCreate() – Tìm Hoặc Tạo Model Trong Laravel | DC SoftTech Tips
- Home
- Eloquent firstOrCreate() – Tìm Hoặc Tạo Model Trong Laravel | DC SoftTech Tips
Trong quá trình phát triển các ứng dụng Laravel tại dcsofttech, việc xử lý dữ liệu trùng lặp khi đồng bộ API, xử lý webhook hoặc nhập liệu hàng loạt là một bài toán thường trực. Thay vì phải viết câu lệnh where()->first() kết hợp với khối điều kiện if/else thủ công, Eloquent cung cấp phương thức firstOrCreate() cực kỳ gọn gàng và tối ưu.
Bài viết này sẽ đi sâu vào cách sử dụng, cú pháp, bản chất câu lệnh SQL sinh ra và những điểm cần lưu ý về hiệu năng khi áp dụng firstOrCreate().
Phương thức firstOrCreate nhận tối đa 3 tham số:
PHP
Model::firstOrCreate(array $attributes, array $values = [])
$attributes: Mảng các điều kiện dùng để tìm kiếm bản ghi trong cơ sở dữ liệu.
$values (Tùy chọn): Mảng chứa các thuộc tính bổ sung sẽ được gán thêm để tạo mới bản ghi nếu không tìm thấy kết quả phù hợp từ $attributes.
Giả sử bạn đang xử lý một hệ thống quản lý bài viết và cần đảm bảo các thẻ (Tag) không bị trùng lặp tên:
PHP
$tag = Tag::firstOrCreate([
'slug' => 'laravel-tips'
]);
Hành động của Eloquent:
Thực hiện câu lệnh truy vấn: SELECT * FROM tags WHERE slug = 'laravel-tips' LIMIT 1.
Nếu tìm thấy, trả về instance của Model Tag hiện tại.
Nếu không tìm thấy, tự động tạo mới một bản ghi với slug = 'laravel-tips' và trả về instance vừa tạo.
Trong nhiều trường hợp, bạn muốn tìm bản ghi bằng một mã định danh (như email hoặc code), nhưng nếu tạo mới thì cần điền thêm các thông tin phụ khác (như name, status).
PHP
$user = User::firstOrCreate(
['email' => 'developer@dcsofttech.com'], // Điều kiện tìm kiếm (WHERE)
[
'name' => 'DC SoftTech Dev',
'role' => 'editor',
'status' => 'active'
] // Giá trị bổ sung khi INSERT
);
Nếu email chưa tồn tại trong cơ sở dữ liệu, Laravel sẽ chạy lệnh INSERT với toàn bộ các trường gộp từ cả hai mảng $attributes và $values.
Khi sử dụng first hoặc create, bạn cần hiểu rõ cơ chế hoạt động bên dưới của Eloquent để tối ưu hóa truy vấn:
Giai đoạn đọc: Laravel thực hiện một câu lệnh SELECT.
Giai đoạn ghi: Nếu không có kết quả, Laravel thực hiện thêm một câu lệnh INSERT.
Vì firstOrCreate() thực hiện hai câu lệnh riêng biệt (SELECT rồi sau đó mới INSERT), trong các hệ thống có độ đồng thời cực cao (high-concurrency request) như xử lý webhook dồn dập hoặc tiến trình Python đa luồng gọi API, bạn có thể gặp lỗi Duplicate entry nếu hai request cùng thực hiện đồng thời bước SELECT và đều không thấy bản ghi, dẫn đến cả hai cùng cố gắng INSERT.
Giải pháp khắc phục:
Luôn đặt Unique Index cho các cột dùng làm điều kiện tìm kiếm ($attributes) trong Migration để database chặn đứng việc trùng lặp ở tầng thấp nhất.
Đối với các tác vụ đòi hỏi khắt khe về độ nguyên tử (atomic), hãy kết hợp khối try-catch xử lý ngoại lệ QueryException mã lỗi trùng khóa (1062 trên MySQL).
Phương thức firstOrCreate() là một vũ khí sắc bén giúp mã nguồn Laravel của bạn trở nên ngắn gọn, sạch sẽ và chuẩn Enterprise hơn khi xử lý dữ liệu đồng bộ. Việc hiểu rõ cơ chế truy vấn kép sẽ giúp bạn thiết kế Database Index hợp lý, tránh các lỗi xung đột dữ liệu ngầm trong các dự án quy mô lớn.