1. Sử dụng các hàm cơ sở dữ liệu trực tiếp qua EF.Functions
Khi thực hiện truy vấn chuỗi, việc dùng
EF.Functions.Like thường cho hiệu suất tốt hơn so với các phương thức tích hợp như
StartsWith,
Contains hay
EndsWith, vì nó sinh ra câu lệnh SQL sử dụng toán tử
LIKE — vốn được tối ưu bởi hầu hết các hệ quản trị cơ sở dữ liệu.
Ví dụ:
Contains("abc") thường được dịch thành biểu thức dùng CHARINDEX (trên SQL Server), dẫn đến việc không thể tận dụng chỉ mục đầy đủ:
var results = context.Users.Where(u => u.Name.Contains("abc")).ToList();
- Trong khi đó,
EF.Functions.Like sinh ra câu lệnh LIKE '%abc%', hỗ trợ kế hoạch thực thi hiệu quả hơn nếu có chỉ mục phù hợp:
var results = context.Users
.Where(u => EF.Functions.Like(u.Name, "%abc%"))
.ToList();
Ngoài ra, các hàm ngày tháng như
EF.Functions.DateDiffDay,
EF.Functions.DateDiffHour, hoặc
EF.Functions.DateDiffMonth giúp tính khoảng cách giữa hai thời điểm mà không cần tải dữ liệu về bộ nhớ để xử lý — toàn bộ phép tính diễn ra tại phía máy chủ CSDL.
2. Mở rộng chức năng với thư viện Z.EntityFramework.Plus.EFCore
Gói mở rộng miễn phí này cung cấp các phương thức khối (bulk operations) giúp tránh vòng lặp và truy vấn dư thừa:
- Xóa hàng loạt không cần tải thực thể trước:
context.Orders.Where(o => o.Status == "Cancelled").DeleteFromQuery();
- Cập nhật trực tiếp trên cơ sở dữ liệu:
context.Customers
.Where(c => c.LastLogin < DateTime.UtcNow.AddDays(-30))
.Update(c => new Customer { IsActive = false });
Lưu ý: Các phiên bản nâng cao (như
Batch Delete/Update với điều kiện phức tạp hoặc hỗ trợ transaction) yêu cầu giấy phép trả phí.
3. Ưu tiên FindAsync() thay vì FirstOrDefaultAsync() khi tra cứu theo khóa chính
Phương thức
FindAsync() kiểm tra đầu tiên trong bộ nhớ đệm (change tracker) trước khi truy vấn cơ sở dữ liệu. Điều này đặc biệt hữu ích khi cùng một thực thể đã được tải trước đó trong cùng scope của
DbContext. Ngược lại,
FirstOrDefaultAsync() luôn phát hành truy vấn mới tới CSDL — gây tổn thất hiệu năng không cần thiết.
4. Vô hiệu hóa theo dõi thực thể khi chỉ đọc dữ liệu
Theo mặc định, EF Core lưu trữ bản sao trạng thái của mọi thực thể được truy vấn nhằm hỗ trợ cập nhật tự động. Nếu bạn chỉ cần đọc dữ liệu (ví dụ: hiển thị danh sách báo cáo), việc tắt cơ chế theo dõi sẽ giảm đáng kể chi phí bộ nhớ và thời gian khởi tạo đối tượng:
var products = await context.Products.AsNoTracking().ToListAsync();
Để áp dụng toàn cục cho một lần truy vấn đa bảng, có thể cấu hình hành vi theo dõi ngay từ đầu:
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
5. Dùng AnyAsync() thay vì CountAsync() hoặc FirstOrDefaultAsync() khi kiểm tra sự tồn tại
Khi mục tiêu chỉ là xác định xem tập kết quả có phần tử nào hay không,
AnyAsync() dừng ngay sau khi tìm thấy phần tử đầu tiên — tương đương với
EXISTS trong SQL. Trong khi đó,
CountAsync() buộc phải đếm toàn bộ kết quả, và
FirstOrDefaultAsync() vẫn tạo đối tượng dù chỉ cần kiểm tra tính tồn tại.
bool hasActiveOrder = await context.Orders.AnyAsync(o => o.UserId == userId && o.Status == "Processing");