我正在使用实体框架,我需要创建一个动态表达式,如:
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,但我需要它与实体框架一起使用。
这意味着我需要解析
item => compiledSel(item) != null && compiledSel(item).ToLower().StartsWith(filter.Value.ToString().ToLower())
到例如。
x => x.Name != null && x.Name.StartsWith("John")
我这样做的原因是因为我希望能够动态过滤多个实体。
有什么建议吗?
修改
针对EF的查询本身在这里运行:
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(....
并且我得到The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
错误
答案 0 :(得分:3)
首先,如果propertyAccess
是字符串属性的访问者,则以下
var sel = Expression.Lambda<Func<TEntity, bool>>(propertyAccess, parameter);
应该是
var sel = Expression.Lambda<Func<TEntity, string>>(propertyAccess, parameter);
其次,Compile
在EF表达式中不起作用。您可以使用Expression
类的方法手动构建整个谓词表达式,但这相对较难。我建议你使用“原型”表达式和简单的参数替换器,如下所示:
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]);
以下是使用的辅助方法的代码:
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);
}
}
}
答案 1 :(得分:1)
Dynamic Linq可能是您的选择:
Repository.People.Where("Name != null && Name.StartsWith(\"John\")")