c# - 在 Expression 中调用 Any 并传递委托(delegate)

标签 c# .net entity-framework linq expression

我这里有一个场景,我需要使用 linq(使用 nhibernate)进行动态查询。最终查询应如下所示:

long[] values = { ... };

var result = Queryable<Entity>.Where(x => x.Documents.Any(d => values.Contains(d.Id)))
                              .ToList();

通用 Entity和属性(property)Documents可以更改,它将由某些用户配置定义。收藏类型DocumentsICollection<T>其中 TDocument类型。我正在尝试创建一个 Expression树来动态定义这些语句,但我遇到了一些问题。查看下面我尝试过的代码和注释。

我创建了这个函数来返回我想在 Any 中使用的委托(delegate)方法:

    public static Func<T, bool> GetFunc<T>(long[] values)
        where T : Entity
    {
        return x => values.Contains(x.Id);
    }

我正在使用 Expression 类来制作这样的表达式(参见代码和注释):

// define my parameter of expression
var parameter = Expression.Parameter(typeof(T), "x");

// I get an array of IDs (long) as argument and transform it on an Expression
var valuesExpression = Expression.Constant(values);

// define the access to my collection property. propertyFilter is propertyinfo for the `Documents` of the sample above.
// I get an expression to represent: x.Documents
var collectionPropertyExpression = Expression.Property(parameter, propertyFilter);

// get the T generic type of the ICollection<T> from propertyFilter. I get the `Documents` of sample above.
var entityFilterType = propertyFilter.PropertyType.GetGenericArguments()[0];

// get the definition of `Any` extension method from `Enumerable` class to make the expression
var anyMethod = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
                                                      .First(x => x.Name == "Any" && x.GetParameters().Length == 2)
                                                      .MakeGenericMethod(entityFilterType);

// get a methodBase for GetFunc to get the delagete to use inside the Any
// using the `Document` generic type
var collectionBody = typeof(LookUpHelper).GetMethod("GetFunc", BindingFlags.Public | BindingFlags.Static)
                                                             .MakeGenericMethod(entityFilterType);

// call the any passing the collection I need and convert it to a Delegate
// I get something like: x => values.Contains(x.Id) ... where x if the `Document`
var func = (Delegate)collectionBody.Invoke(null, new object[] { values });

// get the func as an expression .. maybe the problem is here
var funcExpression = Expression.Constant(func);

// call the any passing the collection and my delagate as arguments
var f = Expression.Call(anyMethod, collectionPropertyExpression, funcExpression);

// I already have an expression and concatenate it using `AndAlso` operator.
body = Expression.AndAlso(body, f);

// finally, I built up to lambda expression and apply it on my queryable
var filterExpression = Expression.Lambda<Func<T, bool>>(body, parameter);

var result = Queryable.Where(filterExpression).ToList();

它一直执行到 ToList 执行查询为止方法。我收到以下错误:

Could not parse expression 'x.Documents.Any(value(System.Func`2[Project.Document,System.Boolean]))': The object of type 'System.Linq.Expressions.ConstantExpression' cannot be converted to type 'System.Linq.Expressions.LambdaExpression'. If you tried to pass a delegate instead of a LambdaExpression, this is not supported because delegates are not parsable expressions.

我不确定我做错了什么。有人可以帮助我吗?

谢谢。

最佳答案

您正在传递 Func哪里有Expression<Func>是期待。前者是委托(delegate),后者是表达式。

public static Expression<Func<T, bool>> GetFunc<T>(long[] values)
      where T : Entity
{
    return x => values.Contains(x.Id);
}

现在您无需使用表达式助手类手动构建表达式,因为您已经有了表达式。

关于c# - 在 Expression 中调用 Any 并传递委托(delegate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43369229/

相关文章:

c# - SEHException .net 难题

c# - Entity Framework 中的连接泄漏

c# - Entity Framework 5.0b2 代码优先 : One-To-Many and One-To-One for the same table, 带级联删除

c# - "The subprocess making the call can not access this object because the owner is another thread"异常异步/等待 WPF C#

c# - 读取 ".NET CLR Exceptions"类别的 Perfmon 计数器

c# - 使用容器实例在 Azure 中未启用访问 Swagger

c# - 用坏字符替换字符串的坏字符

c# - 在 asp.net 中创建连接字符串/连接到数据库?

c# - .NET 中的 JIT 编译器和事件处理程序

c# - SaveFileDialog问题(C#)(VS2008)