Hãy xem xét các đối tượng những thực thể giả tạo:Loại bỏ chọn N + 1 mà không .Include
public class Consumer
{
public int Id { get; set; }
public string Name { get; set; }
public bool NeedsProcessed { get; set; }
public virtual IList<Purchase> Purchases { get; set; } //virtual so EF can lazy-load
}
public class Purchase
{
public int Id { get; set; }
public decimal TotalCost { get; set; }
public int ConsumerId { get; set; }
}
Bây giờ chúng ta hãy nói rằng tôi muốn chạy mã này:
var consumers = Consumers.Where(consumer => consumer.NeedsProcessed);
//assume that ProcessConsumers accesses the Consumer.Purchases property
SomeExternalServiceICannotModify.ProcessConsumers(consumers);
Theo mặc định này sẽ bị ảnh hưởng từ Chọn N + 1 bên trong phương thức ProcessConsumers. Nó sẽ kích hoạt một truy vấn khi nó liệt kê người tiêu dùng, sau đó nó sẽ lấy từng mua bộ sưu tập 1 bằng 1. Các giải pháp tiêu chuẩn cho vấn đề này sẽ có thêm một bao gồm:
var consumers = Consumers.Include("Purchases").Where(consumer => consumer.NeedsProcessed);
//assume that ProcessConsumers accesses the Consumer.Purchases property
SomeExternalServiceICannotModify.ProcessConsumers(consumers);
Đó hoạt động tốt trong nhiều trường hợp, nhưng trong một số trường hợp phức tạp, bao gồm hoàn toàn có thể phá hủy hiệu suất theo đơn đặt hàng của cường độ. Là nó có thể làm điều gì đó như thế này:.
- Lấy người tiêu dùng, người tiêu dùng var của tôi = _entityContext.Consumers.Where (...) ToList()
- Lấy mua hàng của tôi, var mua = _entityContext.Purchases. Ở đâu (...). ToList()
- Hydrate người tiêu dùng. Mua bộ sưu tập theo cách thủ công từ các giao dịch mua tôi đã nạp vào bộ nhớ. Sau đó, khi tôi chuyển nó cho ProcessConsumers, nó sẽ không kích hoạt thêm các truy vấn db.
Tôi không chắc chắn cách thực hiện # 3. Nếu bạn cố gắng truy cập bất kỳ bộ sưu tập người tiêu dùng nào. Mua hàng sẽ kích hoạt tải chậm (và do đó, hãy chọn N + 1). Có lẽ tôi cần phải đưa Người tiêu dùng vào loại thích hợp (thay vì loại proxy của EF) và sau đó tải bộ sưu tập? Một cái gì đó như thế này:
foreach (var consumer in Consumers)
{
//since the EF proxy overrides the Purchases property, this doesn't really work, I'm trying to figure out what would
((Consumer)consumer).Purchases = purchases.Where(x => x.ConsumerId = consumer.ConsumerId).ToList();
}
EDIT: Tôi đã viết lại ví dụ một chút để hy vọng tiết lộ vấn đề này rõ ràng hơn.
IIRC EF sẽ tự động hydrate các bộ sưu tập, vì vậy # 3 không phải được thực hiện thủ công. – jeroenh
Truy vấn đầu tiên của bạn nên thực hiện như một câu lệnh SQL đơn. Bạn có thấy nhiều cuộc gọi db không? –
@Nicholas, bạn nói đúng, tôi đã cập nhật ví dụ để làm cho nó Chọn N + 1. Đây là một ví dụ rất đơn giản, đọc toàn bộ câu hỏi và cố gắng hiểu những gì tôi thực sự yêu cầu. Ví dụ thực tế ở đâu. Bao gồm không đủ phức tạp hơn đáng kể và không hợp lý để đặt bên trong câu hỏi SO. – manu08