2011-09-21 46 views
1

的部分跳出LINQ2SQL表達

private static void Original() 
{ 
    using (var context = new AdventureWorksContext()) 
    { 
     var result = 
      from product in context.Products 
      from workorder in product.WorkOrders 
      select new 
      { 
       productName = product.Name, 
       order = workorder, 
      }; 

     var result2 = 
      from item in result 
      where item.order.WorkOrderRoutings.Count() == 1 
      select item.productName; 

     foreach (var item in result2.Take(10)) 
     { 
      Console.WriteLine(item); 
     } 
    } 
} 

我想打出來的item.order.WorkOrderRoutings.Count()一部分,並與基於某些輸入參數別的東西,像item.order.OrderQty取代我有這段代碼LINQ。

我第一次嘗試:

private static Func<WorkOrder, int> GetRoutingCountFunc() 
{ 
    return workOrder => workOrder.WorkOrderRoutings.Count(); 
} 

private static void RefactoredFunc() 
{ 
    using (var context = new AdventureWorksContext()) 
    { 
     var result = 
      from product in context.Products 
      from workorder in product.WorkOrders 
      select new 
      { 
       productName = product.Name, 
       order = workorder, 
      }; 

     var result2 = 
      from item in result 
      where GetRoutingCountFunc()(item.order) == 1 
      select item.productName; 

     foreach (var item in result2.Take(10)) 
     { 
      Console.WriteLine(item); 
     } 
    } 
} 
當然

失敗,運行時有異常

Method 'System.Object DynamicInvoke(System.Object[])' has no supported translation to SQL.

所以我想通了,我需要把某種Expression。最合理的我可以找出是

private static Expression<Func<WorkOrder, int>> GetRoutingCountExpression() 
{ 
    return workOrder => workOrder.WorkOrderRoutings.Count(); 
} 

private static void RefactoredExpression() 
{ 
    using (var context = new AdventureWorksContext()) 
    { 
     var result = 
      from product in context.Products 
      from workorder in product.WorkOrders 
      select new 
      { 
       productName = product.Name, 
       order = workorder, 
      }; 

     var result2 = 
      from item in result 
      where GetRoutingCountExpression()(item.order) == 0 
      select item.productName; 

     foreach (var item in result2.Take(10)) 
     { 
      Console.WriteLine(item); 
     } 
    } 
} 

但是,讓一個編譯時錯誤:「方法名稱預期」就行了where GetRoutingCountExpression()(item.order) == 0

如果不是匿名類型,我可以創建一個方法返回Expression<Func<"anonType", bool>>並將其用作where參數。

如何分解部分LINQ表達式?

+1

http://www.albahari.com /nutshell/predicatebuilder.aspx你可以試試這個方向 –

+0

+1爲Adrian Iftodes回答。我有完全相同的問題,並最終使用瞭解決我的問題的謂詞構建器。 – wasatz

回答

1

最簡單的方法是創建方法來轉換IQueryable<T>實例。例如這樣的方法:

private static IQueryable<WorkOrder> FilterByRoutingCount(
    IQueryable<WorkOrder> orders, int count) 
{ 
    return 
     from workOrder in orders, 
     where workOrder.WorkOrderRoutings.Count() == count) 
     select workOrder; 
} 

您可以使用此方法是這樣的:

var workorders = 
    from product in context.Products 
    from workorder in product.WorkOrders 
    select workorder; 

var result2 = 
    from workorder in FilterByRoutingCount(workorders, 1) 
    select workorder.Product.productName; 
+0

問題是'result'是一個匿名類型。我不知道如何推出訂單。我在第一個選擇中嘗試從GetRoutingCount(product.WorkOrders,1)'中的工作單「,但是這給了我編譯時錯誤'無法從'System.Data.Linq.EntitySet '轉換爲'System。 Linq.IQueryable ''。 –

+0

@Albin:你可以通過重寫你的LINQ查詢來解決這些問題。嘗試這裏的技巧當然是拋棄匿名類型。查看我的更新。 – Steven

0

你可以簡單地做喜歡:

private static int GetRoutingCount(WorkOrder w) 
{ 
    return w.WorkOrderRoutings.Count(); 
} 

如果我們假設item.order是類型WorkOrder,那麼你可以使用它像:

var result2 = 
    from item in result 
    where GetRoutingCount(item.order) == 0 
    select item.productName; 

編輯

這應該做的工作:

Expression<Func<Tuple<string, Order>, bool>> routingCountZero = x => 
    x.Item2.Roundings.Count == 0; 

你將不得不使用lambda表達式:

var result2 = result.Where(routingCountZero).Select(x => x.Item1); 
+0

你可以(它既可以編譯也可以執行),但是這不會轉化爲單個SQL命令,它會首先枚舉'result',然後爲'result'中的每個項目重複調用'GetRoutingCount',導致對SQL的調用過多服務器。 –