Рассмотрим эти надуманные объекты сущностей:
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; }
}
Теперь предположим, что я хочу запустить этот код:
var consumers = Consumers.Where(consumer => consumer.NeedsProcessed);
//assume that ProcessConsumers accesses the Consumer.Purchases property
SomeExternalServiceICannotModify.ProcessConsumers(consumers);
По умолчанию это будет зависеть от Select N+1 внутри метода ProcessConsumers. Он вызовет запрос, когда перечислит потребителей, а затем захватит каждую коллекцию покупок 1 на 1. Стандартным решением этой проблемы было бы добавить include:
var consumers = Consumers.Include("Purchases").Where(consumer => consumer.NeedsProcessed);
//assume that ProcessConsumers accesses the Consumer.Purchases property
SomeExternalServiceICannotModify.ProcessConsumers(consumers);
Это прекрасно работает во многих случаях, но в некоторых сложных случаях включение может полностью разрушить производительность на порядки. Можно ли сделать что-то вроде этого:
Я не знаю, как сделать #3. Если вы попытаетесь получить доступ к любому потребителю. Коллекция покупок, которая вызовет ленивую загрузку (и, следовательно, Select N+1). Возможно, мне нужно привести Consumers к правильному типу (вместо типа прокси-сервера EF), а затем загрузить коллекцию? Что-то вроде этого:
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();
}
ПРАВКА: Я немного переписал пример, чтобы, надеюсь, раскрыть проблему более четко.