Вызов вложенных выражений Linq.Any () - PullRequest
0 голосов
/ 16 июня 2020

Я использую выражение для генерации запроса linq для вызовов EF. Мне нужно выразить любой через несколько списков, не зная типов, прежде чем я нажму на список. Вот почему я использую это мерзкое отражение.

Мне нужно создать x => x.list.Any( x1 => x1.list.Any(x2 => x2.SearchProp1 == 1)), где x = Class0, x1 = Class1, x2 = Class2

public class Class0 {
    public IEnumerable<Class1> list { get; set; }
    //...Other props
}
public class Class1 {
    public IEnumerable<Class2> list { get; set; }
    //...other props
}

public class Class2 {
    public int? SearchProp1 { get; set; }
    //...other props
}

То, что у меня есть до сих пор, является производным от моего простого средства поиска свойств, то есть работает, но не могу настроить на "любой" звонок. Так что вполне возможно, что весь мой подход неверен.

    public static LambdaExpression GetNavigationPropertySelector(Type type, FilterProp filterProp, params string[] properties) {
        return GetNavigationPropertySelector(properties, 0, filterProp, Expression.Parameter(type, "x"));
    }

    private static LambdaExpression GetNavigationPropertySelector(string[] properties, int depth, FilterProp filterProp, ParameterExpression parameter) {
        var body = GetNavigationPropertyExpression(parameter, properties, depth, filterProp);
        return Expression.Lambda(body, parameter);
    }

    private static Expression GetNavigationPropertyExpression(Expression source, string[] properties, int depth, FilterProp filterProp) {
        if (depth == properties.Length)
            return FilterActionDefinition(source, filterProp);
        var property = Expression.Property(source, properties[depth]);
        if (typeof(IEnumerable).IsAssignableFrom(property.Type)) {
            var elementType = property.Type.GetGenericArguments()[0];
            var parameter = Expression.Parameter(elementType, depth == 0 ? "x" : "x" + depth);
            var elementSelector = GetNavigationPropertySelector(properties, depth + 1, filterProp, parameter);

            var anyMethod = typeof(Enumerable).GetMethods().FirstOrDefault(method => method.Name == "Any" && method.GetParameters().Count() == 2);
            var specificMethod = anyMethod.MakeGenericMethod(elementSelector.Type);

       ---> var lambda = (Expression<Func<something, bool>>)elementSelector; //What to do here?
            return Expression.Call(
                specificMethod,
                lambda,
                elementSelector
            );
        } else {
            return GetNavigationPropertyExpression(property, properties, depth + 1, filterProp);
        }
    }


    private static Expression FilterActionDefinition(Expression left, FilterProp prop) {
        var right = GenerateRightSide(prop, left);

        if (IsNonStringEnumerable(left.Type))
            switch (prop.FilterAction) {
                case PropertyFilterAction.Contains :
                    var containsMethod = typeof(Enumerable).GetMethods()
                    .Where(x => string.Equals(x.Name, "Contains",
                    StringComparison.OrdinalIgnoreCase))
                    .Single(x => x.GetParameters().Length == 2)
                    .MakeGenericMethod(right.Type);
                    return Expression.Call(containsMethod, left, right);
                default : throw new NotImplementedException("This Action is not implemented!");
            }
        return prop.FilterAction switch
        {
            PropertyFilterAction.Equal => Expression.Equal(left, right),
            PropertyFilterAction.LessEqual => Expression.LessThanOrEqual(left, right),
            PropertyFilterAction.LessThan => Expression.LessThan(left, right),
            PropertyFilterAction.MoreEqual => Expression.GreaterThanOrEqual(left, right),
            PropertyFilterAction.MoreThan => Expression.GreaterThan(left, right),
            PropertyFilterAction.Contains => Expression.Call(left, left.Type.GetMethod("Contains", new[] { right.Type }), right),
            PropertyFilterAction.StartsWith => Expression.Call(left, left.Type.GetMethod("StartsWith", new[] { right.Type }), right),
            //case PropertyFilterAction.Select: return Expression.Call(left, left.Type.GetMethod("Select", new[] { right.Type }), right);
            _ => throw new NotImplementedException("This Action is not implemented!"),
        };
    }



    private static Expression GenerateRightSide(FilterProp properties, Expression body) {
        if (!body.Type.GetInterfaces().Contains(typeof(IEnumerable)))
            return Expression.Convert(Expression.Constant(properties.Value), body.Type);
       return Expression.Constant(properties.Value);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...