Как передать список выражений в запросе linq - PullRequest
2 голосов
/ 25 января 2020

Я хочу сделать Generi c Класс для разбиения на страницы с Generi c Параметры поиска. Я использовал отражение, чтобы получить свойства фильтра. Это может быть достигнуто с помощью выражений, о которых я не знаю много. Любая помощь будет оценена.

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 Ответ

1 голос
/ 25 января 2020

Это создаст лямбда-выражение, которое будет пересекать свойства между родовым c типом T и классом Filter и сравнивать их на равенство; каждая отдельная пара свойств объединяется с условием 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)

Это сделает работу, но есть место для оптимизации.

...