[英]PredicateBuilder helper function for create expression
i have an form to search criteria, and i use PredicateBuilder to combine all criteras to an WHere Expression - and the EF generate sql for evaluate in DataBase side. 我有一个搜索条件的表格,并且我使用PredicateBuilder将所有的criteras组合成一个WHere表达式-EF生成sql以在数据库端进行评估。
for allow the user choise between equal, start with, end with and contains, i use asterisk wildcard. 为了允许用户在相等,开头,结尾和包含之间选择,我使用星号通配符。
this my code: 这是我的代码:
var predicate = LinqKit.PredicateBuilder.New<PersonEntity>(true);
{
var arg = parameters.Name;
arg = arg.Trim();
var start = arg[0] == '*';
var end = arg[arg.Length - 1] == '*';
arg = arg.Trim('*');
if (start && end)
predicate.And(x => x.Name.Contains(arg));
else if (start)
predicate.And(x => x.Name.StartsWith(arg));
else if (end)
predicate.And(x => x.Name.EndsWith(arg));
else
predicate.And(x => x.Name == arg);
}
{
var arg = parameters.Address;
arg = arg.Trim();
var start = arg[0] == '*';
var end = arg[arg.Length - 1] == '*';
arg = arg.Trim('*');
if (start && end)
predicate.And(x => x.Address.Contains(arg));
else if (start)
predicate.And(x => x.Address.StartsWith(arg));
else if (end)
predicate.And(x => x.Address.EndsWith(arg));
else
predicate.And(x => x.Address == arg);
}
end ect... 结束...
i want write a generic helper function, for simple use: 我想编写一个通用的辅助函数,以方便使用:
predicate.And(Helper.AddStringCompareCriteria(x => x.Name, parameters.Name);
predicate.And(Helper.AddStringCompareCriteria(x => x.Address, parameters.Address);
my try for now: 我现在尝试:
public static class Helper
{
static Type strType = typeof(string);
static MethodInfo strStart = typeof(string).GetMethod("StartsWith");
static MethodInfo strEnd = typeof(string).GetMethod("EndsWith");
static MethodInfo strContains = typeof(string).GetMethod("Contains");
static MethodInfo strEquals = typeof(string).GetMethod("Equals");
static MethodInfo RightMethod(bool start, bool end)
{
if (start && end)
return strContains;
if (start)
return strStart;
if (end)
return strEnd;
else
return strEquals;
}
public static Expression<Func<T, bool>> AddStringCompareCriteria<T, TResult>(Expression<Func<T, TResult>> member, string toComprae)
{
var arg = toComprae;
arg = arg.Trim();
var start = arg[0] == '*';
var end = arg[arg.Length - 1] == '*';
arg = arg.Trim('*');
MethodInfo method = RightMethod(start, end);
ParameterExpression entityParam = Expression.Parameter(typeof(T), "entity");
return Expression.Lambda<Func<T, bool>>(
Expression.Call(/* get-member-here?*/ , method, new[] { Expression.Constant(arg) }),
entityParam);
}
}
I now do not know how to access the selected member (by the function expression), And I'm not sure I'm in the right direction, I'd be happy to help!. 我现在不知道如何访问选定的成员(通过函数表达式),而且我不确定我的方向正确,很乐意为您提供帮助!
So first off, you need to remove the generic argument TResult
, because your code requires it to be a string. 因此,首先,您需要删除通用参数TResult
,因为您的代码要求它是字符串。 Just replace all usages of that type with string
, because any other type won't work with this method. 只需用string
替换该类型的所有用法,因为任何其他类型都无法使用此方法。
Next, rather than trying to build up the whole expression "by hand", it's far better to construct an expression that takes a string and computes a boolean using the appropriate comparison function, and then to just combine that expression with the provided expression. 接下来,与其尝试“手工”构建整个表达式,不如构造一个采用字符串并使用适当的比较函数计算布尔值的表达式,然后将该表达式与提供的表达式组合起来,这要好得多。 In general I'd say that you want to avoid building expressions by hand whenever you can possibly avoid it. 总的来说,我想说,只要有可能,就避免手工构建表达式。 Your code will be shorter, easier to understand, and importantly statically verified by the compiler . 您的代码将更短,更容易理解,并且重要地由编译器进行静态验证 。
So we'll start by adapting your RightMethod
to return an Expression
: 因此,我们将首先调整您的RightMethod
以返回Expression
:
static Expression<Func<string, bool>> ComparisonExpression(bool start, bool end, string toCompare)
{
if (start && end)
return value => value.Contains(toCompare);
if (start)
return value => value.StartsWith(toCompare);
if (end)
return value => value.EndsWith(toCompare);
else
return value => value.Equals(toCompare);
}
Next we'll need a way of composing two expressions together. 接下来,我们需要一种将两个表达式组合在一起的方法。 Here we have to build it by hand, but it can be written to compose any two arbitrary expression , so that we don't need to re-write the code every time two expressions need to be combined. 在这里,我们必须手动构建它,但是可以编写它来组成任意两个任意表达式 ,这样就不必在每次需要将两个表达式组合在一起时都重新编写代码。
public static Expression<Func<TSource, TResult>> Compose<TSource, TIntermediate, TResult>(
this Expression<Func<TSource, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second)
{
var param = Expression.Parameter(typeof(TSource));
var intermediateValue = first.Body.ReplaceParameter(first.Parameters[0], param);
var body = second.Body.ReplaceParameter(second.Parameters[0], intermediateValue);
return Expression.Lambda<Func<TSource, TResult>>(body, param);
}
Which uses the following code to actually replace the parameters: 它使用以下代码实际替换参数:
public static Expression ReplaceParameter(this Expression expression,
ParameterExpression toReplace,
Expression newExpression)
{
return new ParameterReplaceVisitor(toReplace, newExpression)
.Visit(expression);
}
public class ParameterReplaceVisitor : ExpressionVisitor
{
private ParameterExpression from;
private Expression to;
public ParameterReplaceVisitor(ParameterExpression from, Expression to)
{
this.from = from;
this.to = to;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return node == from ? to : base.Visit(node);
}
}
And now your method is pretty trivial, as it's doing almost nothing other than calling out to our two methods: 现在,您的方法非常简单,因为除了调用我们的两个方法外,几乎什么也没做:
public static Expression<Func<T, bool>> AddStringCompareCriteria<T>(Expression<Func<T, string>> member, string toCompare)
{
toCompare = toCompare.Trim();
var start = toCompare[0] == '*';
var end = toCompare[toCompare.Length - 1] == '*';
toCompare = toCompare.Trim('*');
return member.Compose(ComparisonExpression(start, end, toCompare));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.