简体   繁体   English

PredicateBuilder帮助函数,用于创建表达式

[英]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.

相关问题 PredicateBuilder创建条件条件列表 - PredicateBuilder to create a list of where conditions C#将表达式作为参数传递并使用PredicateBuilder - C# Pass expression as argument and use PredicateBuilder 如何围绕Url.Content辅助函数创建包装器帮助器? - How to create a wrapper helper around Url.Content helper function? 我可以创建一个与Linq一起使用的辅助函数吗? - Can I create a helper function to use with Linq? 创建一个返回Razor @标签的辅助函数? - Create a helper function that returns Razor @ tags? 我可以将角度表达式的结果传递给HTML帮助器函数吗 - Can I pass the result of angular expression to Html helper function 如何创建一个辅助函数,该函数调用作为参数传递的其他函数 - How a create a helper function which calls other functions passed as parameter C# PredicateBuilder Entities:在指定的 LINQ to Entities 查询表达式中未绑定参数“f” - C# PredicateBuilder Entities: The parameter 'f' was not bound in the specified LINQ to Entities query expression 嵌套PredicateBuilder谓词:“参数&#39;f&#39;在指定的LINQ to Entities查询表达式中未绑定” - Nesting PredicateBuilder predicates : 'The parameter 'f' was not bound in the specified LINQ to Entities query expression' 具有DateTime的PredicateBuilder - PredicateBuilder with DateTime
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM