0

我很难确定处理这个问题的最佳方法......使用实体框架(和 L2S),LINQ 查询返回 IQueryable。我已经阅读了关于 DAL/BLL 是否应该返回 IQueryable、IEnumerable 或 IList 的各种意见。假设我们使用 IList,那么查询会立即运行,并且该控制不会传递到下一层。这使得单元测试等变得更容易。您失去了在更高级别细化查询的能力,但您可以简单地创建另一个方法,允许您细化查询并仍然返回 IList。还有更多的优点/缺点。到现在为止还挺好。

现在是实体框架和延迟加载。我在 .NET 4/VS 2010 中使用带有代理的 POCO 对象。在表示层中,我这样做:

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

在这种情况下,GetOrders() 返回 IList,因此它在返回 PL 之前立即执行。但是在下一个 foreach 中,您有延迟加载,它在获取所有 OrderLine 时执行多个 SQL 查询。所以基本上,PL 在错误的层“按需”运行 SQL 查询。

有什么明智的方法可以避免这种情况吗?我可以关闭延迟加载,但是拥有这个每个人都在抱怨 EF1 没有的“功能”又有什么意义呢?而且我承认它在许多情况下都非常有用。所以我看到了几个选择:

  1. 以某种方式删除实体中的所有关联并添加方法以返回它们。这违背了默认的 EF 行为/代码生成,并且使得执行一些复合(多实体)LINQ 查询变得更加困难。这似乎是倒退了一步。我投反对票。
  2. 如果我们仍然有延迟加载,这使得单元测试变得困难,那么就一直返回 IQueryable。您将拥有更多的控制权。我仍然认为这不是一个好的选择,因为 IQueryable 将您与 L2S、L2E 或您自己的 IQueryable 完整实现联系在一起。延迟加载可能会“按需”运行查询,但不会将您绑定到任何特定界面。我投反对票。
  3. 关闭延迟加载。您必须手动处理您的关联。这可能是急切加载的 .Include()。在某些特定情况下,我投赞成票。
  4. 保持 IList 和延迟加载。在很多情况下,我投赞成票,只是因为与其他人的麻烦。

还有其他选择或建议吗?我还没有找到真正让我信服的选项。

4

1 回答 1

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

高温高压

于 2010-05-08T17:05:20.757 回答