2012-10-15 93 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 
       };