2010-05-07 4 views
0

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

Теперь идет платформа 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-запросов, поскольку она получает все OrderLines. Так что в основном PL выполняет SQL-запросы «по требованию» в неправильном слое.

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

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

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

ответ

0

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

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)) 

HTH

+0

Вы не покрывал «отложенной загрузки/выполнение SQL от слоя пользовательского интерфейса», но это все еще помогает. Я думаю, что последний фрагмент кода ближе всего к тому, что я ищу. Кажется, что у вас 1) простота использования, 2) инкапсуляция/SoC/unit-testable/etc., 3) возможность использования расширенных функций (загружаемая загрузка и т. Д.). Выбери два. У вас не может быть всех троих. В любом случае, спасибо за вашу помощь. –