2011-09-21 45 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的调用过多服务器。 –