动态LINQ,选择功能,可以枚举,但不可查询 [英] Dynamic LINQ, Select function, works on Enumerable, but not Queryable

查看:212
本文介绍了动态LINQ,选择功能,可以枚举,但不可查询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在动摇LINQ一段时间,但我还没有学习它的秘密。



我有一个表达式,我想解析那个样子像这样:

 document.LineItems.Select(i =&i; i.Credit).Sum() 

在解析期间,我到达了一个需要在LineItems集合上调用Select函数的点。我使用Expression.Call的工厂方法:

  Expression.Call(
typeof(Queryable),
Select,
new Type [] {typeof(LineItem),typeof(decimal?)},
expr,
Expression.Lambda(expression,new ParameterExpression [] {Expression.Parameter (typeof(LineItem)}));

此刻

  expr:document.LineItems [ICollection< LineItem>] 
表达式:LineItem.Credit [decimal?]

目前还没有实现,我只是在构建表达式树。



现在,问题:



此Expresssion.Call抛出和异常:无通用方法'选择'类型'System.Linq.Queryable'与提供的类型兼容参数和参数;



我可以通过在System.Linq.Enumerable中查找Select,而不是可查询来解决它愤怒的第一个参数Expression.Call。



但是,这不是我想要的。我不希望所有LineItems只能计算Sum(),这显然是Enumerable的情况。我想要Queryable工作。



另外,对于解析的最后一部分 - Sum(),我还需要使用Enumerable Sum(),因为Queryable Sum()抛出相同的异常。



我已经检查了MSDN,选择功能的两个签名都是相同的,所以我真的看不出为什么一个工作和其他工作。 >

任何帮助或指针将被aprreciated。



注意,

解决方案

问题是 LineItems 是一个 ICollection< LineItem> Queryable.Select 的第一个参数需要一个 IQueryable< LineItem> ICollection< T> 仅实现 IEnumerable< T> ,这就是为什么它适用于 Enumerable。选择



您需要将 expr 的类型更改为<$你可以使用 Queryable.AsQueryable / code>方法。以下函数创建一个表达式来计算给定的文档实例的信用属性值:

 code> public static Expression< Func< decimal?>>> CreateSumLineItemsExpr(Document document)
{
var docExpr = Expression.Constant(document);
var itemsExpr = Expression.Property(docExpr,LineItems);

表达式< Func< LineItem,decimal?>>> selector = i => i.Credit;
var queryableExpr = Expression.Call(typeof(Queryable),AsQueryable,new [] {typeof(LineItem)},itemsExpr);
var selectExpr = Expression.Call(typeof(Queryable),Select,new [] {typeof(LineItem),typeof(decimal?)},queryableExpr,selector);
var sumExpr = Expression.Call(typeof(Queryable),Sum,null,selectExpr);

返回Expression.Lambda }


I have been fiddling with dynamic LINQ for some time now, but I have yet to learn its secrets.

I have an expression that I want to parse that looks like this:

"document.LineItems.Select(i => i.Credit).Sum();"

During parsing of this I reach a point where I need to call a Select function on LineItems Collection. I am using factory method of Expression.Call:

Expression.Call(
    typeof(Queryable),
    "Select",
    new Type[] { typeof(LineItem), typeof(decimal?) },
    expr,
    Expression.Lambda(expression, new ParameterExpression[] { Expression.Parameter(typeof(LineItem) }));

At this moment

expr:          document.LineItems    [ICollection<LineItem>]  
expression:    LineItem.Credit       [decimal?]

none of which is materialized yet. I am just building Expression Tree at the moment.

Now, the problem:

This Expresssion.Call throws and Exception: "No generic method 'Select' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments";

I resolve it easily by looking for 'Select' in 'System.Linq.Enumerable' instead of 'Queryable' by changing first argument of Expression.Call.

But, that's not quite that I want. I don't want all LineItems hauled in only to calculate Sum(), which would obviously be case with Enumerable. I want Queryable to work.

Also, for the last part of parsing - Sum(), I also need to go with Enumerable Sum(), because Queryable Sum() throws same Exception.

I have checked MSDN, both signatures of 'Select' function are identical, so i really cannot see why would one work and other not.

Any help or pointers would be aprreciated.

Regards,

解决方案

The problem is that LineItems is an ICollection<LineItem>, while the first parameter to Queryable.Select requires an IQueryable<LineItem>. ICollection<T> only implements IEnumerable<T> which is why it works for Enumerable.Select.

You will need to change the type of expr to be IQueryable<LineItem>.

You should be able to do this with the Queryable.AsQueryable method. The following function creates an expression to sum the credit property values for a given Document instance:

public static Expression<Func<decimal?>> CreateSumLineItemsExpr(Document document)
{
    var docExpr = Expression.Constant(document);
    var itemsExpr = Expression.Property(docExpr, "LineItems");

    Expression<Func<LineItem, decimal?>> selector = i => i.Credit;
    var queryableExpr = Expression.Call(typeof(Queryable), "AsQueryable", new[] { typeof(LineItem) }, itemsExpr);
    var selectExpr = Expression.Call(typeof(Queryable), "Select", new[] { typeof(LineItem), typeof(decimal?) }, queryableExpr, selector);
    var sumExpr = Expression.Call(typeof(Queryable), "Sum", null, selectExpr);

    return Expression.Lambda<Func<decimal?>>(sumExpr);
}

这篇关于动态LINQ,选择功能,可以枚举,但不可查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆