如何在linq查询中传递表达式列表

时间:2020-01-25 15:28:15

标签: c# linq lambda expression

我想使用通用搜索参数创建用于分页的通用类。我使用反射来获取滤镜属性。可以使用我不太了解的表达式来实现。任何帮助将不胜感激。

public IEnumerable<T> ModelPagination(F filters) <-- F class filter properties eg. Name, CNIC for search
        {
            Type C = Type.GetType("filters");
            PropertyInfo[] properties = C.GetProperties();

            foreach (PropertyInfo prop in properties)
            {
                 prop.Name;
            }

            return dbEntity.Where(x => ...... ).ToList(); <--- want to pass each property as lambda for something like x -> x.Name == filters.Name || filters.Name == Null 

        }

1 个答案:

答案 0 :(得分:2)

这将构建lambda表达式,该表达式将与通用类型TFilter类之间的属性相交,并比较它们的相等性,而且每个单独的属性对都与AND条件组合。

public static IEnumerable<T> ModelPagination<T>(F filter) 
{
        // all properties which are in the fiter class also present in the generic type T
        var commonPropertyNames = filter
                .GetType()
                .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                .Select(x => x.Name)
                .Intersect(
                    typeof(T)
                    .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                    .Select(x => x.Name)
                );
        var argumentExpression = Expression.Parameter(typeof(T), "x");
        var filterConstantExpression = Expression.Constant(filter);

        // build the expression
        var expression = (BinaryExpression)null;
        foreach (var propertyName in commonPropertyNames)
        {
            var filterPropertyExpression = Expression.Property(filterConstantExpression, propertyName);

            var equalExpression = Expression.Equal(
                Expression.Property(argumentExpression, propertyName),
                filterPropertyExpression
            );

            var nullCheckExpression = Expression.Equal(
                filterPropertyExpression,
                Expression.Constant(null)
            );

            var orExpression = Expression.OrElse(equalExpression, nullCheckExpression);

            if (expression == null)
            {
                expression = orExpression;
            }
            else
            {
                expression = Expression.AndAlso(expression, orExpression);
            }
        }

        var lambda = Expression.Lambda<Func<T, bool>>(expression, argumentExpression);

        return dbContext.Entry<T>().Where(lambda).ToList();
    }

如果您拥有T这样的{ FirstName, LastName }类型和Filter这样的{ FirstName }类 它将创建以下表达式

x => x.FirstName == filter.FirstName || filter.FirstName == null

如果您拥有T这样的{ FirstName, LastName }类型和Filter这样的{ FirstName, LastName }类 它将创建以下表达式

x => (x.FirstName == filter.FirstName || filter.FirstName == null) 
     && (x.LastName == filter.LastName || filter.LastName == null)

这可以完成工作,但是还有优化的空间。