Вопрос

Мне трудно определить лучший способ справиться с этим...При использовании Entity Framework (и L2S) запросы LINQ возвращают IQueryable.Я читал различные мнения о том, должен ли DAL/BLL возвращать IQueryable, IEnumerable или IList.Если мы используем IList, то запрос выполняется немедленно, и управление не передается на следующий уровень.Это упрощает модульное тестирование и т. д.Вы теряете возможность уточнять запрос на более высоких уровнях, но можете просто создать другой метод, который позволит уточнить запрос и при этом возвращать IList.И еще много плюсов/минусов.Все идет нормально.

Теперь идет Entity Framework и отложенная загрузка.Я использую объекты POCO с прокси в .NET 4/VS 2010.На уровне представления я делаю:

foreach (Order order in bll.GetOrders())
{
  foreach (OrderLine orderLine in order.OrderLines)
  {
    // Do something
  }
}

В этом случае GetOrders() возвращает IList, поэтому он выполняется непосредственно перед возвратом в PL.Но в следующем foreach у вас есть отложенная загрузка, которая выполняет несколько запросов SQL по мере получения всех строк заказа.По сути, PL выполняет SQL-запросы «по требованию» не на том уровне.

Есть ли разумный способ избежать этого?Я мог бы отключить отложенную загрузку, но тогда какой смысл в этой «функции», на которую все жаловались, что в EF1 ее нет?И я признаю, что это очень полезно во многих сценариях.Поэтому я вижу несколько вариантов:

  1. Каким-то образом удалите все ассоциации в сущностях и добавьте методы для их возврата.Это противоречит поведению/генерации кода EF по умолчанию и усложняет выполнение некоторых составных (множественных сущностей) запросов LINQ.Это похоже на шаг назад.Я голосую нет.
  2. Если у нас все равно отложенная загрузка, что затрудняет модульное тестирование, тогда пройдите до конца и верните IQueryable.Дальше по слоям у вас будет больше контроля.Я все еще не думаю, что это хороший вариант, поскольку IQueryable привязывает вас к L2S, L2E или вашей собственной полной реализации IQueryable.Отложенная загрузка может выполнять запросы «по требованию», но не привязывает вас к какому-либо конкретному интерфейсу.Я голосую нет.
  3. Отключите отложенную загрузку.Вам придется обрабатывать ассоциации вручную.Это может быть с помощью функции .Include() с активной загрузкой.Я голосую за в некоторых конкретных случаях.
  4. Сохраняйте IList и отложенную загрузку.Во многих случаях я голосую за, только из-за проблем с остальными.

Есть еще варианты или предложения?Я не нашел варианта, который бы меня действительно убедил.

Это было полезно?

Решение

Вы можете заставить свои методы принимать какую-то стратегию загрузки.

Func<ObjectSet<Order>, ObjectQuery<Order>> loadSpan = 
orders=> orders.Include("OrderLines");

foreach (Order order in bll.GetOrders(loadSpan)) 
{ 
  foreach (OrderLine orderLine in order.OrderLines) 
  { 
    // Do something 
  } 
}

И внутри вашего метода GetOrders вы делаете что-то вроде

public IList<Oorder> GetOrders(
                     Func<ObjectSet<Order>, ObjectQuery<Order>> loadSpan)
{ 
    var ordersWithSpan = loadSpan(context.OrderSet);
    var orders = from order in ordersWithSpan
                 where ...your normal filters etc

    return orders.ToList();
}

Это позволит вам указать целые графики нагрузки для каждого варианта использования.Вы, конечно, также можете обернуть эти стратегии в какой-нибудь класс-оболочку, чтобы написать:

//wrapped in a static class "OrderLoadSpans"
foreach (Order order in bll.GetOrders(OrderLoadSpans.WithOrderLines))

ХТХ

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top