Việc gỡ lỗi các truy vấn cơ sở dữ liệu trong Entity Framework Core đôi khi có thể cảm giác như đang tìm kim trong đống cỏ. Khi ứng dụng của bạn tạo ra hàng chục hoặc hàng trăm truy vấn SQL, việc xác định truy vấn LINQ nào đã tạo ra câu lệnh SQL cụ thể đã trở thành một thách thức thực sự.
May mắn thay, tôi đã phát hiện ra một giải pháp tinh tế mà EF Core cung cấp: Query Tags.
Mục lục
Query Tags
Query Tags cho phép bạn thêm các nhận xét tùy chỉnh vào các truy vấn SQL được tạo ra bởi các biểu thức LINQ. Các nhận xét này xuất hiện trực tiếp trong SQL được tạo ra, giúp việc truy ngược lại từ một truy vấn SQL đến mã cụ thể đã tạo ra nó trở nên vô cùng dễ dàng.
Để sử dụng tính năng này, bạn cần áp dụng phương thức TagWith
vào bất kỳ IQueryable
nào và truyền một nhận mô tả:
var expensiveOrders = context.Orders<br>
.TagWith("Finding orders over $1000 for quarterly report")<br>
.Where(o => o.Total > 1000)<br>
.Include(o => o.Customer)<br>
.ToList();
Mã này tạo ra SQL trông như thế này:
-- Finding orders over $1000 for quarterly report<br>SELECT [o].[Id], [o].[CustomerId], [o].[Total], [c].[Id], [c].[Name]<br>FROM [Orders] AS [o]<br>INNER JOIN [Customers] AS [c] ON [o].[CustomerId] = [c].[Id]<br>WHERE [o].[Total] > 1000.0
Thay vì phải cố gắng đảo ngược mã nào đã tạo ra một truy vấn SQL cụ thể, bạn có thể ngay lập tức thấy mục đích và nguồn gốc của mỗi truy vấn trong nhật ký cơ sở dữ liệu hoặc trình phân tích của bạn.
Kỹ thuật nâng cao
Kết nối nhiều tag
Bạn có thể kết nối nhiều lệnh gọi TagWith
để thêm ngữ cảnh bổ sung:
var userOrders = context.Orders<br>
.TagWith("User dashboard query")<br>
.TagWith($"User ID: {userId}")<br>
.TagWith("Performance critical - cache results")<br>
.Where(o => o.CustomerId == userId)<br>
.OrderByDescending(o => o.OrderDate)<br>
.Take(10)<br>
.ToList();
Mã này tạo ra:
-- User dashboard query<br>-- User ID: 12345<br>-- Performance critical - cache results
Lưu ý: Mặc dù tác động hiệu suất của TagWith
là tối thiểu, hãy tránh các tag quá dài hoặc nội dung chuỗi phức tạp trong các đường dẫn nóng.
Tag động với ngữ cảnh
Bạn có thể tạo các tag động bao gồm thông tin thời gian chạy:
public async Task<List<Product>> GetProductsByCategoryAsync(int categoryId, string correlationId)<br>{<br> return await context.Products<br> .TagWith($"GetProductsByCategory - CategoryId: {categoryId}, CorrelationId: {correlationId}")<br> .Where(p => p.CategoryId == categoryId)<br> .ToListAsync();<br>}
Lưu ý: Tôi thích sử dụng điều này để chuyển correlation id của OpenTelemetry như bạn có thể thấy trong ví dụ trên. Điều này giúp cung cấp khả năng theo dõi từ đầu đến cuối.