C # Aggregate для свойства Expression возвращает AmbiguousMatchException - PullRequest
0 голосов
/ 31 октября 2018

У меня есть следующие (упрощенные) классы:

public abstract class BaseSite
{
    public int SiteId { get; set; }
    public string Name { get; set; }
}

public class OptionalSite : BaseSite
{
    public new int? SiteId { get; set; }
}

И следующий метод:

    public static Expression<Func<T, bool>> PredicateExtension<T>(this IQueryable<T> source, string member, object value, string expression)
    {
        ParameterExpression item = Expression.Parameter(typeof(T), "item");
        Expression memberValue = member.Split('.').Aggregate((Expression)item, Expression.PropertyOrField);
        Type memberType = memberValue.Type;
        if (value != null && value.GetType() != memberType)
            value = Convert.ChangeType(value, memberType);
        Expression condition = null;
        switch (expression)
        {
            case "==":
                condition = Expression.Equal(memberValue, Expression.Constant(value, memberType));
                break;
            case "!=":
                condition = Expression.NotEqual(memberValue, Expression.Constant(value, memberType));
                break;
            case "<":
                condition = Expression.LessThan(memberValue, Expression.Constant(value, memberType));
                break;
            case ">":
                condition = Expression.GreaterThan(memberValue, Expression.Constant(value, memberType));
                break;
            case "<=":
                condition = Expression.LessThanOrEqual(memberValue, Expression.Constant(value, memberType));
                break;
            case ">=":
                condition = Expression.GreaterThanOrEqual(memberValue, Expression.Constant(value, memberType));
                break;
            default:
                break;
        }
        if (condition == null)
            condition = Expression.Equal(memberValue, Expression.Constant(value, memberType));
        var predicate = Expression.Lambda<Func<T, bool>>(condition, item);

        return predicate;
    }

Теперь при вызове метода со следующими параметрами:

LinqExtentions.PredicateExtension<OptionalSite>(SiteDbSet, "SiteId", 1, "==");

У меня есть следующая проблема: Во второй строке метода есть вызов Aggregate, но это дает мне AmbiguousMatchException. Причина в том, что свойство SiteId определено как в базовом классе, так и в классе OptionalSite (public new ...) ...

Итак, вопрос здесь: как я могу получить правильное выражение, используя этот (или другой) метод? Возможно, мне потребуется получить тот же результат Expression, но с использованием другого способа его получения, чтобы при обнаружении свойств в базовом классе и реализованном классе я мог выбрать свойство в классе, который реализует базовый класс.

EDIT:

Тип SiteId изменяется с int на int?. Другие классы, которые реализуют этот базовый класс, должны иметь его как обязательное свойство (EF), но для этого класса это необязательное свойство. Из-за этого я не могу использовать ключевое слово virtual в своем базовом классе.

1 Ответ

0 голосов
/ 31 октября 2018

Для получения информации о том, почему вы получили AmbiguousMatchException и как ее решить, вы можете посмотреть этот ответ.

Вы должны использовать более продвинутую функцию:

Expression memberValue = member.Split('.').Aggregate((Expression)item, (expr, name) =>
{
    // get all properties with matching name
    var properties = expr.Type.GetProperties().Where(p => p.Name == name);
    // if only one found, use that, else use the one that is declared in the derived type
    var property = properties.Count() == 1 ? properties.First() : properties.Single(p => p.DeclaringType == expr.Type);
    // make expression from this PropertyInfo
    return Expression.Property(expr, property);
});

Обратите внимание, что это просто базовый подход. Он не учитывает поля (не должно быть проблемой с EF), и может быть несколько уровней наследования со свойством, объявленным где-то между ними. Но вы поняли.

...