打破LINQ2SQL Expression的部分内容

时间:2011-09-21 19:05:44

标签: c# .net linq linq-to-sql expression-trees

我有这条LINQ代码

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

我的第一次尝试:

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

当然没有带有异常的运行时

  

方法'System.Object DynamicInvoke(System.Object [])'没有支持的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表达式的部分内容?

2 个答案:

答案 0 :(得分: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;

答案 1 :(得分: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);