Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用于针对标记化字符串生成string.contains的动态Linq查询的通用函数_Linq_Dynamic Linq - Fatal编程技术网

用于针对标记化字符串生成string.contains的动态Linq查询的通用函数

用于针对标记化字符串生成string.contains的动态Linq查询的通用函数,linq,dynamic-linq,Linq,Dynamic Linq,我正在使用Expression.And和Expression.Or构建动态linq查询。当查询的属性/字段是字符串,并且字符串包含空格时,我希望在空格上标记该字符串,并在标记上创建一个“and'd”子查询 这里是我的意思,以一种非通用的方式 var tokens = Code.Split(new []{" "}, StringSplitOptions.RemoveEmptyEntries); var index = 0; var firstToken = tokens[index ++]; E

我正在使用
Expression.And
Expression.Or
构建动态linq查询。当查询的属性/字段是字符串,并且字符串包含空格时,我希望在空格上标记该字符串,并在标记上创建一个“and'd”子查询

这里是我的意思,以一种非通用的方式

var tokens = Code.Split(new []{" "}, StringSplitOptions.RemoveEmptyEntries);
var index = 0;

var firstToken = tokens[index ++];
Expression<Func<Entity, bool>> subQuery =
                                 entity => entity.Code.Contains(firstToken);

for (; index < tokens.Length; index ++)
{
    var tempToken = tokens[index];
    subQuery = subQuery.And(entity => entity.Code.Contains(tempToken));
}

query = query.Or(subQuery);

我也很想知道这一切看起来是否是个坏主意。

以下是我用来做这件事的方法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Collections.ObjectModel;

namespace MyLibrary.Extensions
{
    /// <summary>Defines extension methods for building and working with Expressions.</summary>
    public static class ExpressionExtensions
    {
        /// <summary>Ands the Expressions.</summary>
        /// <typeparam name="T">The target type of the Expression.</typeparam>
        /// <param name="expressions">The Expression(s) to and.</param>
        /// <returns>A new Expression.</returns>
        public static Expression<Func<T, bool>> And<T>(this IEnumerable<Expression<Func<T, bool>>> expressions)
        {
            if (expressions.IsNullOrEmpty())
                return null;

            Expression<Func<T, bool>> finalExpression = expressions.First();

            foreach (Expression<Func<T, bool>> e in expressions.Skip(1))
                finalExpression = finalExpression.And(e);

            return finalExpression;
        }

        /// <summary>Ors the Expressions.</summary>
        /// <typeparam name="T">The target type of the Expression.</typeparam>
        /// <param name="expressions">The Expression(s) to or.</param>
        /// <returns>A new Expression.</returns>
        public static Expression<Func<T, bool>> Or<T>(this IEnumerable<Expression<Func<T, bool>>> expressions)
        {
            if (expressions.IsNullOrEmpty())
                return null;

            Expression<Func<T, bool>> finalExpression = expressions.First();

            foreach (Expression<Func<T, bool>> e in expressions.Skip(1))
                finalExpression = finalExpression.Or(e);

            return finalExpression;
        }

        /// <summary>Ands the Expression with the provided Expression.</summary>
        /// <typeparam name="T">The target type of the Expression.</typeparam>
        /// <param name="expression1">The left Expression to and.</param>
        /// <param name="expression2">The right Expression to and.</param>
        /// <returns>A new Expression.</returns>
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2)
        {
            //Reuse the first expression's parameter
            ParameterExpression param = expression1.Parameters.Single();
            Expression left = expression1.Body;
            Expression right = RebindParameter(expression2.Body, expression2.Parameters.Single(), param);
            BinaryExpression body = Expression.AndAlso(left, right);

            return Expression.Lambda<Func<T, bool>>(body, param);
        }

        /// <summary>Ors the Expression with the provided Expression.</summary>
        /// <typeparam name="T">The target type of the Expression.</typeparam>
        /// <param name="expression1">The left Expression to or.</param>
        /// <param name="expression2">The right Expression to or.</param>
        /// <returns>A new Expression.</returns>
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2)
        {
            //Reuse the first expression's parameter
            ParameterExpression param = expression1.Parameters.Single();
            Expression left = expression1.Body;
            Expression right = RebindParameter(expression2.Body, expression2.Parameters.Single(), param);
            BinaryExpression body = Expression.OrElse(left, right);

            return Expression.Lambda<Func<T, bool>>(body, param);
        }

        /// <summary>Updates the supplied expression using the appropriate parameter.</summary>
        /// <param name="expression">The expression to update.</param>
        /// <param name="oldParameter">The original parameter of the expression.</param>
        /// <param name="newParameter">The target parameter of the expression.</param>
        /// <returns>The updated expression.</returns>
        private static Expression RebindParameter(Expression expression, ParameterExpression oldParameter, ParameterExpression newParameter)
        {
            if (expression == null)
                return null;

            switch (expression.NodeType)
            {
                case ExpressionType.Parameter:
                {
                    ParameterExpression parameterExpression = (ParameterExpression)expression;

                    return (parameterExpression.Name == oldParameter.Name ? newParameter : parameterExpression);
                }
                case ExpressionType.MemberAccess:
                {
                    MemberExpression memberExpression = (MemberExpression)expression;

                    return memberExpression.Update(RebindParameter(memberExpression.Expression, oldParameter, newParameter));
                }
                case ExpressionType.AndAlso:
                case ExpressionType.OrElse:
                case ExpressionType.Equal:
                case ExpressionType.NotEqual:
                case ExpressionType.LessThan:
                case ExpressionType.LessThanOrEqual:
                case ExpressionType.GreaterThan:
                case ExpressionType.GreaterThanOrEqual:
                {
                    BinaryExpression binaryExpression = (BinaryExpression)expression;

                    return binaryExpression.Update(RebindParameter(binaryExpression.Left, oldParameter, newParameter), binaryExpression.Conversion, RebindParameter(binaryExpression.Right, oldParameter, newParameter));
                }
                case ExpressionType.Call:
                {
                    MethodCallExpression methodCallExpression = (MethodCallExpression)expression;

                    return methodCallExpression.Update(RebindParameter(methodCallExpression.Object, oldParameter, newParameter), methodCallExpression.Arguments.Select(arg => RebindParameter(arg, oldParameter, newParameter)));
                }
                case ExpressionType.Invoke:
                {
                    InvocationExpression invocationExpression = (InvocationExpression)expression;

                    return invocationExpression.Update(RebindParameter(invocationExpression.Expression, oldParameter, newParameter), invocationExpression.Arguments.Select(arg => RebindParameter(arg, oldParameter, newParameter)));
                }
                default:
                {
                    return expression;
                }
            }
        }

        public static Expression<Func<T, bool>> BuildContainsExpression<T, R>(Expression<Func<T, R>> valueSelector, IEnumerable<R> values)
        {
            if (null == valueSelector)
                throw new ArgumentNullException("valueSelector");

            if (null == values)
                throw new ArgumentNullException("values");

            ParameterExpression parameterExpression = valueSelector.Parameters.Single();
            IEnumerable<BinaryExpression> equalExpressions = null;
            Expression aggregationExpression = null;

            if (!values.IsNullOrEmpty())
                return (e => false);

            equalExpressions = values.Select(v => Expression.Equal(valueSelector.Body, Expression.Constant(v, typeof(R))));
            aggregationExpression = equalExpressions.Aggregate<Expression>((accumulate, equal) => Expression.Or(accumulate, equal));

            return Expression.Lambda<Func<T, bool>>(aggregationExpression, parameterExpression);
        }

        public static Expression<Func<T, bool>> BuildDoesNotContainExpression<T, R>(Expression<Func<T, R>> valueSelector, IEnumerable<R> values)
        {
            if (null == valueSelector)
                throw new ArgumentNullException("valueSelector");

            ParameterExpression parameterExpression = valueSelector.Parameters.Single();
            IEnumerable<BinaryExpression> notEqualExpressions = null;
            Expression aggregationExpression = null;

            if (!values.IsNullOrEmpty())
                return (e => false);

            notEqualExpressions = values.Select(v => Expression.NotEqual(valueSelector.Body, Expression.Constant(v, typeof(R))));
            aggregationExpression = notEqualExpressions.Aggregate<Expression>((accumulate, equal) => Expression.And(accumulate, equal));

            return Expression.Lambda<Func<T, bool>>(aggregationExpression, parameterExpression);
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Linq.Expressions;
使用System.Collections.ObjectModel;
命名空间MyLibrary.Extensions
{
///定义用于构建和使用表达式的扩展方法。
公共静态类表达式扩展
{
///这是表达方式。
///表达式的目标类型。
///表达式到和。
///一个新的表达。
公共静态表达式和(此IEnumerable表达式)
{
if(expressions.IsNullOrEmpty())
返回null;
Expression finalExpression=expressions.First();
foreach(表达式中的表达式e.Skip(1))
最终压力=最终压力。和(e);
返回最终压力;
}
///这些表达都很有趣。
///表达式的目标类型。
///表达式指向或。
///一个新的表达。
公共静态表达式或(此IEnumerable表达式)
{
if(expressions.IsNullOrEmpty())
返回null;
Expression finalExpression=expressions.First();
foreach(表达式中的表达式e.Skip(1))
最终压力=最终压力。或(e);
返回最终压力;
}
///将表达式与提供的表达式相加。
///表达式的目标类型。
///左表达式指向和。
///和的正确表达式。
///一个新的表达。
公共静态表达式和(此表达式表达式1、表达式2)
{
//重用第一个表达式的参数
ParameterExpression param=expression1.Parameters.Single();
表达式左=表达式1.主体;
表达式right=RebindParameter(expression2.Body,expression2.Parameters.Single(),param);
BinaryExpression body=Expression.AndAlso(左、右);
返回表达式.Lambda(body,param);
}
///使用提供的表达式替换表达式。
///表达式的目标类型。
///或的左表达式。
///或的正确表达。
///一个新的表达。
公共静态表达式或(此表达式表达式表达式1、表达式表达式表达式2)
{
//重用第一个表达式的参数
ParameterExpression param=expression1.Parameters.Single();
表达式左=表达式1.主体;
表达式right=RebindParameter(expression2.Body,expression2.Parameters.Single(),param);
BinaryExpression body=Expression.OrElse(左、右);
返回表达式.Lambda(body,param);
}
///使用适当的参数更新提供的表达式。
///要更新的表达式。
///表达式的原始参数。
///表达式的目标参数。
///更新后的表达式。
私有静态表达式RebindParameter(表达式表达式、参数Expression oldParameter、参数Expression newParameter)
{
if(表达式==null)
返回null;
开关(表达式.节点类型)
{
大小写表达式类型。参数:
{
ParameterExpression ParameterExpression=(ParameterExpression)表达式;
返回(parameterExpression.Name==oldParameter.Name?newParameter:parameterExpression);
}
case ExpressionType.MemberAccess:
{
MemberExpression MemberExpression=(MemberExpression)表达式;
返回memberExpression.Update(重新绑定参数(memberExpression.Expression,oldParameter,newParameter));
}
case ExpressionType.AndAlso:
case ExpressionType.OrElse:
大小写表达式类型。相等:
case ExpressionType.NotEqual:
case ExpressionType.LessThan:
case ExpressionType.lessthanRequire:
大小写表达式类型。大于:
大小写表达式type.greaterthanor相等:
{
BinaryExpression BinaryExpression=(BinaryExpression)表达式;
返回binaryExpression.Update(RebindParameter(binaryExpression.Left,oldParameter,newParameter)、binaryExpression.Conversion、RebindParameter(binaryExpression.Right,oldParameter,newParameter));
}
大小写表达式类型。调用:
{
MethodCallExpression MethodCallExpression=(MethodCallExpression)表达式;
返回methodCallExpression.Update(重新绑定参数(methodCallExpression.Object,oldParameter,newParameter),methodCallExpression.Arguments.Select(arg=>RebindParameter(arg,oldParameter,newParameter));
}
case ExpressionType.Invoke:
{
调用表达式调用表达式=(调用表达式)表达式;
返回invocationExpression.Update(RebindParameter(invocationExpression.Expression,oldParameter,newParameter),invocationExpression.Arguments.Select(arg=>RebindParameter(arg,oldParameter,newParameter));
private Expression<Func<T, bool>> BuildTokenizedStringQuery<T>(string[] tokens,
                                                    Func<T, string> stringProp)
{
    var index = 0;
    var firstToken = tokens[index++];
    Expression<Func<T, bool>> subQuery = entity => 
                                       stringProp(entity).Contains(firstToken);
    for (; index < tokens.Length; index++)
    {
        var tempToken = tokens[index];
        subQuery = subQuery.And(
                             entity => stringProp(entity).Contains(tempToken));
    }

    return subQuery;
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Collections.ObjectModel;

namespace MyLibrary.Extensions
{
    /// <summary>Defines extension methods for building and working with Expressions.</summary>
    public static class ExpressionExtensions
    {
        /// <summary>Ands the Expressions.</summary>
        /// <typeparam name="T">The target type of the Expression.</typeparam>
        /// <param name="expressions">The Expression(s) to and.</param>
        /// <returns>A new Expression.</returns>
        public static Expression<Func<T, bool>> And<T>(this IEnumerable<Expression<Func<T, bool>>> expressions)
        {
            if (expressions.IsNullOrEmpty())
                return null;

            Expression<Func<T, bool>> finalExpression = expressions.First();

            foreach (Expression<Func<T, bool>> e in expressions.Skip(1))
                finalExpression = finalExpression.And(e);

            return finalExpression;
        }

        /// <summary>Ors the Expressions.</summary>
        /// <typeparam name="T">The target type of the Expression.</typeparam>
        /// <param name="expressions">The Expression(s) to or.</param>
        /// <returns>A new Expression.</returns>
        public static Expression<Func<T, bool>> Or<T>(this IEnumerable<Expression<Func<T, bool>>> expressions)
        {
            if (expressions.IsNullOrEmpty())
                return null;

            Expression<Func<T, bool>> finalExpression = expressions.First();

            foreach (Expression<Func<T, bool>> e in expressions.Skip(1))
                finalExpression = finalExpression.Or(e);

            return finalExpression;
        }

        /// <summary>Ands the Expression with the provided Expression.</summary>
        /// <typeparam name="T">The target type of the Expression.</typeparam>
        /// <param name="expression1">The left Expression to and.</param>
        /// <param name="expression2">The right Expression to and.</param>
        /// <returns>A new Expression.</returns>
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2)
        {
            //Reuse the first expression's parameter
            ParameterExpression param = expression1.Parameters.Single();
            Expression left = expression1.Body;
            Expression right = RebindParameter(expression2.Body, expression2.Parameters.Single(), param);
            BinaryExpression body = Expression.AndAlso(left, right);

            return Expression.Lambda<Func<T, bool>>(body, param);
        }

        /// <summary>Ors the Expression with the provided Expression.</summary>
        /// <typeparam name="T">The target type of the Expression.</typeparam>
        /// <param name="expression1">The left Expression to or.</param>
        /// <param name="expression2">The right Expression to or.</param>
        /// <returns>A new Expression.</returns>
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2)
        {
            //Reuse the first expression's parameter
            ParameterExpression param = expression1.Parameters.Single();
            Expression left = expression1.Body;
            Expression right = RebindParameter(expression2.Body, expression2.Parameters.Single(), param);
            BinaryExpression body = Expression.OrElse(left, right);

            return Expression.Lambda<Func<T, bool>>(body, param);
        }

        /// <summary>Updates the supplied expression using the appropriate parameter.</summary>
        /// <param name="expression">The expression to update.</param>
        /// <param name="oldParameter">The original parameter of the expression.</param>
        /// <param name="newParameter">The target parameter of the expression.</param>
        /// <returns>The updated expression.</returns>
        private static Expression RebindParameter(Expression expression, ParameterExpression oldParameter, ParameterExpression newParameter)
        {
            if (expression == null)
                return null;

            switch (expression.NodeType)
            {
                case ExpressionType.Parameter:
                {
                    ParameterExpression parameterExpression = (ParameterExpression)expression;

                    return (parameterExpression.Name == oldParameter.Name ? newParameter : parameterExpression);
                }
                case ExpressionType.MemberAccess:
                {
                    MemberExpression memberExpression = (MemberExpression)expression;

                    return memberExpression.Update(RebindParameter(memberExpression.Expression, oldParameter, newParameter));
                }
                case ExpressionType.AndAlso:
                case ExpressionType.OrElse:
                case ExpressionType.Equal:
                case ExpressionType.NotEqual:
                case ExpressionType.LessThan:
                case ExpressionType.LessThanOrEqual:
                case ExpressionType.GreaterThan:
                case ExpressionType.GreaterThanOrEqual:
                {
                    BinaryExpression binaryExpression = (BinaryExpression)expression;

                    return binaryExpression.Update(RebindParameter(binaryExpression.Left, oldParameter, newParameter), binaryExpression.Conversion, RebindParameter(binaryExpression.Right, oldParameter, newParameter));
                }
                case ExpressionType.Call:
                {
                    MethodCallExpression methodCallExpression = (MethodCallExpression)expression;

                    return methodCallExpression.Update(RebindParameter(methodCallExpression.Object, oldParameter, newParameter), methodCallExpression.Arguments.Select(arg => RebindParameter(arg, oldParameter, newParameter)));
                }
                case ExpressionType.Invoke:
                {
                    InvocationExpression invocationExpression = (InvocationExpression)expression;

                    return invocationExpression.Update(RebindParameter(invocationExpression.Expression, oldParameter, newParameter), invocationExpression.Arguments.Select(arg => RebindParameter(arg, oldParameter, newParameter)));
                }
                default:
                {
                    return expression;
                }
            }
        }

        public static Expression<Func<T, bool>> BuildContainsExpression<T, R>(Expression<Func<T, R>> valueSelector, IEnumerable<R> values)
        {
            if (null == valueSelector)
                throw new ArgumentNullException("valueSelector");

            if (null == values)
                throw new ArgumentNullException("values");

            ParameterExpression parameterExpression = valueSelector.Parameters.Single();
            IEnumerable<BinaryExpression> equalExpressions = null;
            Expression aggregationExpression = null;

            if (!values.IsNullOrEmpty())
                return (e => false);

            equalExpressions = values.Select(v => Expression.Equal(valueSelector.Body, Expression.Constant(v, typeof(R))));
            aggregationExpression = equalExpressions.Aggregate<Expression>((accumulate, equal) => Expression.Or(accumulate, equal));

            return Expression.Lambda<Func<T, bool>>(aggregationExpression, parameterExpression);
        }

        public static Expression<Func<T, bool>> BuildDoesNotContainExpression<T, R>(Expression<Func<T, R>> valueSelector, IEnumerable<R> values)
        {
            if (null == valueSelector)
                throw new ArgumentNullException("valueSelector");

            ParameterExpression parameterExpression = valueSelector.Parameters.Single();
            IEnumerable<BinaryExpression> notEqualExpressions = null;
            Expression aggregationExpression = null;

            if (!values.IsNullOrEmpty())
                return (e => false);

            notEqualExpressions = values.Select(v => Expression.NotEqual(valueSelector.Body, Expression.Constant(v, typeof(R))));
            aggregationExpression = notEqualExpressions.Aggregate<Expression>((accumulate, equal) => Expression.And(accumulate, equal));

            return Expression.Lambda<Func<T, bool>>(aggregationExpression, parameterExpression);
        }
    }
}
string query = "kill mockingbird";
string[] tokens = query.Split(' ');
Expression<Func<Book, string>> inClause = BuildContainsExpression<Book, string>(o => o.Title, tokens);

using (LibraryDataContext dataContext = new LibraryDataContext())
{
    List<Book> matchingBooks = dataContext.Books.Where(inClause).ToList();
}
public static Expression<Func<T, bool>>
           BuildTokenizedStringQuery<T>(string[] tokens,
                             Expression<Func<T, string>> stringPropertyAccessor)
{
    ParameterExpression parameterExpression = stringPropertyAccessor.Parameters
                                                                    .Single();

    var index = 0;
    var firstToken = tokens[index ++];

    Expression<Func<string, bool>> contains =
                                      aString => aString.Contains(firstToken);
    var invocation = Expression.Invoke(contains, stringPropertyAccessor.Body);

    Expression<Func<T, bool>> expression = Expression
                         .Lambda<Func<T, bool>>(invocation, parameterExpression);

    for (; index < tokens.Length; index++)
    {
        var tempToken = tokens[index];

        contains = aString => aString.Contains(tempToken);
        invocation = Expression.Invoke(contains, stringPropertyAccessor.Body);

        expression = expression.And(Expression
                        .Lambda<Func<T, bool>>(invocation, parameterExpression));
    }

    return expression;
}