2012-10-15 68 views
2

我有一个查询,看起来像这样的结果:选择自IEnumerable加入一个复杂的LINQ到SQL查询

var orderLines = from Order order in _orders 
       join OrderItem orderItem in dbc.OrderItems 
        on order.OrderId equals orderItem.OrderId 
       join Product product in dbc.Products 
        on orderItem.ProductId equals product.ProductId 
       join OrderItemQuantity oiq in dbc.OrderItemQuantities 
        on orderItem.OrderItemId equals oiq.OrderItemId 
        into orderItemQuantities 
       join ActivityQuantity aq in dbc.ActivityQuantities 
        on orderItem.OrderItemId equals aq.OrderItemId 
        into activityQuantities 
       orderby 
        order.OrderId ascending, 
        orderItem.OrderLineNumber ascending 
       select new { 
        Order = order, 
        Item = orderItem, 
        Product = product, 
        // I'd like to get these child items as IEnumerables or similar 
        ItemQuantities = orderItemQuantities, 
        ActivityQuantities = activityQuantities 
       }; 

编译没有问题,但导致orderItemQuantitiesactivityQuantities部分是从失踪查询,所以我得到一个选择/加盟/加盟订单/项目/产品,以及独立的个体上OIQ/AQ的每个条目选择:

SELECT (...) FROM [ORDERS] AS t0 
INNER JOIN [ORDER_ITEMS] AS t1 ON t0.ORDER_ID = t1.ORDER_ID 
INNER JOIN [PRODUCTS] AS t2 ON t1.PRODUCT_ID = t2.PRODUCT_ID 
ORDER BY (...) 

然后,为每个行的,它执行这些查询:

SELECT (...) FROM [ACTIVITY_QUANTITY] as t0 
WHERE t0.ORDER_ITEM_ID = @p0 

SELECT (...) FROM [ORDER_ITEM_QUANTITY] as t0 
WHERE t0.ORDER_ITEM_ID = @p0 

由于我有数以万计的行,这导致了一个荒谬的数量的查询。

有没有办法凝聚了OrderItemOrderItemQuantityActivityQuantity条目为IEnumerable(或类似)的方式,使他们很容易从在选择使用的匿名类型访问?

回答

0

不知道这是否会与LINQ工作,SQL,但你可以尝试

   select new { 
       Order = order, 
       Item = orderItem, 
       Product = product, 
       // I'd like to get these child items as IEnumerables or similar 
       ItemQuantities = orderItemQuantities.ToList(), 
       ActivityQuantities = activityQuantities.ToList() 
      }; 

这我相当肯定会在实体框架的工作。

+0

这是不是简单地将仍然执行单个查询每次'递延枚举创建一个IList的'' IEnumerator.MoveNext'被调用? **更新:**是的,证实它只是简单地将底层枚举器转换为'IList ',并且查询仍然是分开的。 – Polynomial

+0

@Polynomial一个耻辱。然后删除这个答案。 EF为你列出清单:( – AakashM

+0

不要删除答案,它可能会帮助其他人排除这种可能性。 – Polynomial

0

我设法自己解决了这个问题。这是不完全的内存友好的,但它的工作原理:

// build a base query that only selects the order, item and product entities 
var orderLinesBase = from Order order in _orders 
      join OrderItem orderItem in dbc.OrderItems 
       on order.OrderId equals orderItem.OrderId 
      join Product product in dbc.Products 
       on orderItem.ProductId equals product.ProductId 
      orderby 
       order.OrderId ascending, 
       orderItem.OrderLineNumber ascending 
      select new { 
       Order = order, 
       Item = orderItem, 
       Product = product 
      }; 

// get all OrderItemQuantity entities that are applicable to the orderLinesBase query 
var orderItemQuantities = (from Order in _orders 
          join OrderItem orderItem in dbc.OrderItems 
           on order.OrderId equals orderItem.OrderId 
          join OrderItemQuantity oiq in dbc.OrderItemQuantities 
           on orderItem.OrderItemId equals oiq.OrderItemId 
          select oiq).ToArray(); 

// get all ActivityQuantity entities that are applicable to the orderLinesBase query 
var activityQuantities = (from Order in _orders 
          join OrderItem orderItem in dbc.OrderItems 
           on order.OrderId equals orderItem.OrderId 
          join ActivityQuantity aq in dbc.ActivityQuantities 
           on orderItem.OrderItemId equals aq.OrderItemId 
          select aq).ToArray(); 

// notice that the above two queries use ToArray to force evaluation of the expression. 

// this is just some cast by example trickery, to help with anonymous types 
// it's just this method: List<T> CastListByExample<T>(T t) { return new List<T>(); } 
var orderLines = Helpers.CastListByExample(new { 
    Order = (Order)null, 
    Item = (OrderItem)null, 
    Product = (Product)null, 
    ItemQuantities = (IEnumerable<OrderItemQuantity>)null, 
    ActivityQuantities = (IEnumberable<ActivityQuantity>)null }); 

// manually fill the list 
foreach (var orderLine in orderLinesBase) 
    orderLines.Add(new 
    { 
     Order = orderLine.Order, 
     Item = orderLine.Item, 
     Product = orderLine.Product, 
     // use a method to filter the quantity data sets manually, because 
     // LINQ won't work with memory-backed enumerables 
     ItemQuantities = FilterByOrderItemId(orderItemQuantities, orderLine.Item.OrderItemId), 
     ActivityQuantities = FilterByOrderItemId(activityQuantities, orderLine.Item.OrderItemId) 
    }); 

不完全是简洁的,在有些地方非常哈克,但它的工作。我总共获得6个查询,而不是数千个查询。

0

尝试在内部联接之前执行组联接。您要执行一组的方式加入每个orderItem,而不是针对每个内部联接的结果:

var orderLines = from OrderItem orderItem in dbc.OrderItems 
       join OrderItemQuantity oiq in dbc.OrderItemQuantities 
        on orderItem.OrderItemId equals oiq.OrderItemId 
        into orderItemQuantities 
       join ActivityQuantity aq in dbc.ActivityQuantities 
        on orderItem.OrderItemId equals aq.OrderItemId 
        into activityQuantities 
       join Order order in _orders 
        on orderItem.OrderId equals order.OrderId 
       join Product product in dbc.Products 
        on orderItem.ProductId equals product.ProductId 
       orderby 
        order.OrderId ascending, 
        orderItem.OrderLineNumber ascending 
       select new { 
        Order = order, 
        Item = orderItem, 
        Product = product, 
        // I'd like to get these child items as IEnumerables or similar 
        ItemQuantities = orderItemQuantities, 
        ActivityQuantities = activityQuantities 
       };