Построение дерева выражений для вызова любого метода в коллекции IQueryable (вложенный запрос) - PullRequest
0 голосов
/ 10 июля 2020

Я пытаюсь создать метод расширения до IQueryable, который будет проверять, есть ли какие-либо совпадающие элементы в свойстве навигации. Что я делаю за пределами кода ниже, так это перебираю свойства типа и проверяю, является ли это свойство свойством навигации, используя IModel.

У меня проблемы с попыткой выяснить, как построить дерево выражений для отношений "один ко многим". Я хочу добиться чего-то вроде Entity.Collections.Any(Collection => Collection.Name == 'Filter'), которое тогда будет предложением where основного запроса. Внутреннее предложение построено за пределами приведенного ниже примера, но я считаю, что ошибка возникает до достижения этого выражения.

Я думаю, что тип делегата Lambda, вероятно, построен неправильно, поскольку он не возвращает bool, он возвращает IEnumerable<Collection>, но я не могу понять, как это должно быть построено, если не так.

Я пытаюсь следовать этому руководству из документации Microsoft.

Строки кода, которые пытаются решить то, что упомянуто выше:

if (typeof(IEnumerable).IsAssignableFrom(targetType))
{
    var targetEntity = targetType.GetGenericArguments().First();
    var subArgument = Expression.Parameter(targetEntity, targetEntity.Name);

    var delegateType = typeof(Func<,>).MakeGenericType(targetEntity, typeof(bool));
    var lambda = Expression.Lambda(delegateType, innerClause, Expression.Parameter(targetEntity));

    Expression.Call(
        typeof(Queryable),
        "Any",
        new Type[] { targetEntity },
        Expression.Property(argument, property.Name),
        lambda
    );
}

Я получаю следующую ошибку в строке, где я пытаюсь создать Expression.Call.

Exception thrown: 'System.InvalidOperationException' in System.Linq.Expressions.dll: 'No generic method 'Any' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic. '

Я также пытался получить любой метод и вызвать его:

var anyMethod = typeof(Queryable)
    .GetMethods()
    .Where(m => m.Name == "Any" && m.IsGenericMethodDefinition)
    .Where(m => m.GetParameters().ToList().Count == 2)
    .First();

var genericMethod = anyMethod.MakeGenericMethod(entityType);

genericMethod.Invoke(Expression.Property(argument, property.Name), new object[] { innerClause, subArgument });

И тогда вместо этого я получаю эту ошибку:

Exception thrown: 'System.ArgumentException' in System.Private.CoreLib.dll: 'Object of type 'System.Linq.Expressions.MethodCallExpression3' cannot be converted to type 'System.Linq.IQueryable 1 [Коллекция] '.' «

Любая помощь приветствуется!

1 Ответ

0 голосов
/ 11 июля 2020

Хорошо, может быть, вопрос был немного неясным из-за того, что я точно не знал, как его задать, но, если кто-то наткнется на вопрос, я решил его следующим образом:

if (typeof(IEnumerable).IsAssignableFrom(targetType))
{
    var targetEntity = targetType.GetGenericArguments().First();
    var subArgument = Expression.Parameter(targetEntity, targetEntity.Name);

    var anyMethod = typeof(Enumerable)
        .GetMethods()
        .Where(m => m.Name == "Any" && m.IsGenericMethodDefinition)
        .Where(m => m.GetParameters().ToList().Count == 2)
        .First();

    anyMethod = GetAnyMethod().MakeGenericMethod(targetType);

    Expression.Call(anyMethod, Expression.MakeMemberAccess(argument, property), Expression.Lambda(x, subArgument));
}

Итак, Основная проблема заключалась в том, что я пытался вызвать метод на Queryable, а не на Enumerable, что у меня должно было быть, поскольку я вызывал метод для свойства, а не для запрашиваемого объекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...