C# 参数为复杂对象时的参数替换
我正在尝试创建一个动态C# 参数为复杂对象时的参数替换,c#,linq,expression-trees,expressionvisitor,C#,Linq,Expression Trees,Expressionvisitor,我正在尝试创建一个动态AndAlso过滤器,该过滤器将在Where方法中用于LINQ to EF查询: query.Where(filterExpression) 其中,filterExpression是一个已编译的lambda 到目前为止,我已经实现了一个具有一些奇特用法的循环,用于检查只有一个、两个或多个查询的情况 Expression selectLeft = null; Expression selectRight = null; Expression filterExpression
AndAlso
过滤器,该过滤器将在Where
方法中用于LINQ to EF
查询:
query.Where(filterExpression)
其中,filterExpression
是一个已编译的lambda
到目前为止,我已经实现了一个具有一些奇特用法的循环,用于检查只有一个、两个或多个查询的情况
Expression selectLeft = null;
Expression selectRight = null;
Expression filterExpression = null;
foreach (QueryColumn columnQuery in querycolumns)
{
Expression<Func<FileColumnRecords, bool>>
columnPredicate = d => d.fcv.Any(f => (f.value != null ?
f.value.ToLower().Contains(columnQuery.queryTerm.ToLower()) :
false));
if (selectLeft == null)
{
selectLeft = columnPredicate.Body;
filterExpression = selectLeft;
continue;
}
if (selectRight == null)
{
selectRight = columnPredicate.Body;
filterExpression =
Expression.AndAlso(selectLeft, selectRight);
continue;
}
filterExpression =
Expression.AndAlso(filterExpression, columnPredicate.Body);
}
它由以下各项构成:
class ParameterReplacer : ExpressionVisitor
{
private readonly ParameterExpression parameter;
internal ParameterReplacer(ParameterExpression parameter)
{
this.parameter = parameter;
}
protected override Expression VisitParameter
(ParameterExpression node)
{
return parameter;
}
}
(ParameterReplace
class由提供)
运行ParameterReplace
时,出现以下错误:
"Property 'System.String value' is not defined for type 'Models.FileColumnRecords'"
其中FileColumnRecords
定义为:
public class FileColumnRecords
{
public Documents doc;
public IEnumerable<FileColumnValues> fcv;
}
我猜想,由于表达式树中嵌入了参数,所以您遇到了困难。替换程序应仅替换顶级参数 您可以将顶级表达式传递到
ParameterReplace
:
class ParameterReplacer : ExpressionVisitor
{
private readonly ParameterExpression target;
private readonly ISet<ParameterExpression> sources;
internal ParameterReplacer(ParameterExpression target,
IEnumerable<LambdaExpression> expressions)
{
this.target = target;
sources = new HashSet<ParameterExpression>(
expressions.SelectMany(e => e.Parameters));
}
protected override Expression VisitParameter
(ParameterExpression node)
{
return sources.Contains(node) ? target : node;
}
}
类参数replacer:ExpressionVisitor
{
私有只读参数表达式目标;
专用只读ISet源;
内部ParameterReplace(ParameterExpression目标,
(可数表达式)
{
this.target=目标;
sources=新哈希集(
expressions.SelectMany(e=>e.Parameters));
}
受保护的重写表达式VisitParameter
(ParameterExpression节点)
{
返回源。包含(节点)?目标:节点;
}
}
然后,您需要更改代码的其余部分,以建立已组合的表达式树列表。当然还有更优雅的方式,但我认为这应该行得通。这是我脑子里想不出来的,我还没试过
说了这么多,你确定你不能只用它来代替吗?基于JonSkeet的观点,我使用了JonSkeet从库中建议的一种惊人的方法,提出了以下简单的解决方案:
public static IQueryable<FileColumnRecords> DynamicColumnQuery
(this IQueryable<FileColumnRecords> query,
List<QueryColumn> querycolumns)
{
var predicate = PredicateBuilder.False<FileColumnRecords>();
foreach (QueryColumn columnQuery in querycolumns)
{
string temp = columnQuery.queryTerm.ToLower();
predicate = predicate.Or(d => d.fcv.Any(f => (f.value != null ?
f.value.ToLower().Contains(temp) : false));
}
return query.AsExpandable().Where(predicate);
}
公共静态IQueryable动态列查询
(此IQueryable查询,
列表查询列)
{
var predicate=PredicateBuilder.False();
foreach(QueryColumn column在querycolumns中查询)
{
string temp=columnQuery.queryTerm.ToLower();
谓词=谓词。或(d=>d.fcv.Any)(f=>(f.value!=null?
f、 value.ToLower()包含(temp:false));
}
返回query.AsExpandable().Where(谓词);
}
如果您对编写表达式树略知一二,那么您将立即体会到这是多么令人难以置信的AWESOME。另外,请注意我是如何在谓词中嵌入参数的
我与LINQKit、Joseph或Ben Albahari的开发者没有任何关系
也不是O'Reilly出版社。只是一个非常满意的开发人员,他认为我应该
分享他们建造的令人敬畏的建筑
谢谢你的回复,Jon!
PredicateBuilder
看起来真的很有趣。你认为可以将我的整个ColumnPricate
传递给PredicateBuilder
或者我必须按照你在回答中的建议构建一个表达式树吗?@Seacookie:我不太明白你在做什么,但我怀疑你可以整个columnPredicate
。这绝对值得一试。让我把这个拿出来试驾。天哪,Jon!PredicateBuilder
真是太棒了!!谢谢你。
class ParameterReplacer : ExpressionVisitor
{
private readonly ParameterExpression target;
private readonly ISet<ParameterExpression> sources;
internal ParameterReplacer(ParameterExpression target,
IEnumerable<LambdaExpression> expressions)
{
this.target = target;
sources = new HashSet<ParameterExpression>(
expressions.SelectMany(e => e.Parameters));
}
protected override Expression VisitParameter
(ParameterExpression node)
{
return sources.Contains(node) ? target : node;
}
}
public static IQueryable<FileColumnRecords> DynamicColumnQuery
(this IQueryable<FileColumnRecords> query,
List<QueryColumn> querycolumns)
{
var predicate = PredicateBuilder.False<FileColumnRecords>();
foreach (QueryColumn columnQuery in querycolumns)
{
string temp = columnQuery.queryTerm.ToLower();
predicate = predicate.Or(d => d.fcv.Any(f => (f.value != null ?
f.value.ToLower().Contains(temp) : false));
}
return query.AsExpandable().Where(predicate);
}