Lambda中的动态where子句 [英] Dynamic where clause in lambda

查看:106
本文介绍了Lambda中的动态where子句的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用实体框架,并且需要创建一个动态表达式,例如:

I am using entity framework, and I need to create a dynamic expressions like:

var sel = Expression.Lambda<Func<TEntity, bool>>(propertyAccess, parameter);
var compiledSel = sel.Compile();
// sel = x.Name
// filter.Value = "John"
Repository.GetData.Where(item => compiledSel(item) != null && compiledSel(item).ToLower().StartsWith(filter.Value.ToString().ToLower()))

以上内容适用于IQueriable,但我需要它与实体框架一起使用.

The above works with IQueriable, but I need it to work with entity framework.

这意味着我需要解析

item => compiledSel(item) != null && compiledSel(item).ToLower().StartsWith(filter.Value.ToString().ToLower())

例如

x => x.Name != null && x.Name.StartsWith("John")

之所以这样做,是因为我有多个实体,希望能够动态过滤.

The reason I am doing this is because I have multiple entities I want to be able to filter dynamically.

有什么建议吗?

针对EF的查询本身在此处运行:

The query itself against EF is run here:

private IList<TEntity> GetCollection(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, object>>[] includes)
{
    return DbSet 
     .Where(where)
     .ApplyIncludes(includes)
     .ToList();
}

现在运行查询时,数据where子句为 Param_0 =>(((((Invoke(value(.... ,我得到 LINQ to Entities不支持LINQ表达式节点类型'Invoke'.错误

When I run the query now the data where clause is Param_0 => (((Invoke(value(.... and I get The LINQ expression node type 'Invoke' is not supported in LINQ to Entities. error

推荐答案

首先,如果 propertyAccess 是字符串属性的访问者,则以下内容

First off, if the propertyAccess is accessor to a string property, the following

var sel = Expression.Lambda<Func<TEntity, bool>>(propertyAccess, parameter);

应该是

var sel = Expression.Lambda<Func<TEntity, string>>(propertyAccess, parameter);

第二, Compile 在EF表达式中不起作用.您可以使用 Expression 类的方法手动构建整个谓词表达式,但这比较困难.我建议您使用这样的原型"表达式和简单的参数替换器:

Second, the Compile does not work inside the EF expressions. You can build the whole predicate expression manually using the methods of the Expression class, but that's relatively hard. What I could suggest you is to use a "prototype" expression and simple parameter replacer like this:

var selector = Expression.Lambda<Func<TEntity, string>>(propertyAccess, parameter);

var value = filter.Value.ToString().ToLower();

Expression<Func<string, bool>> prototype = 
    item => item != null && item.ToLower().StartsWith(value);

var predicate = Expression.Lambda<Func<T, bool>>(
    prototype.Body.ReplaceParameter(prototype.Parameters[0], selector.Body), 
    selector.Parameters[0]);

这是所使用的辅助方法的代码:

Here is the code of the used helper method:

public static class ExpressionUtils
{
    public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
    {
        return new ParameterReplacer { Source = source, Target = target }.Visit(expression);
    }

    class ParameterReplacer : ExpressionVisitor
    {
        public ParameterExpression Source;
        public Expression Target;
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return node == Source ? Target : base.VisitParameter(node);
        }
    }
}

这篇关于Lambda中的动态where子句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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