Ausdrucksbaum für untergeordnete Auflistungsliste .Irgendein

c# expression-trees lambda linq

Frage

Ich erstelle generische Linq-Abfrage mit Ausdrucksbaum. Ich stehe fest, wenn ich einen Ausdruck in der Kindersammlung erzeuge. Methodenaufruf explodiert wegen inkompatibler Typen. Normalerweise weiß ich, was ich dort setzen soll, aber der Methodenaufruf Any () hat mich verwirrt. Ich habe jeden möglichen Typ ausprobiert und kein Glück. Jede Hilfe wäre willkommen.

Hier ist meine Entitätsklasse:

public class Story : Entity
{
    public string Author { get; set; }

    public IList<string> Contributors { get; set; }
}

Abfrage, für die ich einen Ausdrucksbaum erzeugen möchte:

var stories = new List<Story>();
stories.Where(p => p.Author.Contains("Test") || p.Contributors.Any(c => c.Contains("Test")));

Was ich bisher habe

public interface IFilterCriteria
{
    string PropertyToCompare { get; set; }
    object ValueToCompare { get; set; }
    FilterOperator FilterOperator { get; set; }
    bool IsList { get; set; }
    Expression Expression { get; set; }
}

public static IQueryable<T> Filter<T>(this IQueryable<T> query, IList<IFilterCriteria> filterCriterias, LogicalOperator logicalOperator = LogicalOperator.And)
{
    if (filterCriterias != null && filterCriterias.Any())
    {
        var resultCondition = filterCriterias.ToExpression(query, logicalOperator);

        var parameter = Expression.Parameter(query.ElementType, "p");

        if (resultCondition != null)
        {
            var lambda = Expression.Lambda(resultCondition, parameter);

            var mce = Expression.Call(
                typeof(Queryable), "Where",
                new[] { query.ElementType },
                query.Expression,
                lambda);

            return query.Provider.CreateQuery<T>(mce);
        }
    }
    return query;
}

public static Expression ToExpression<T>(this IList<IFilterCriteria> filterCriterias, IQueryable<T> query, LogicalOperator logicalOperator = LogicalOperator.And)
{
    Expression resultCondition = null;
    if (filterCriterias.Any())
    {
        var parameter = Expression.Parameter(query.ElementType, "p");

        foreach (var filterCriteria in filterCriterias)
        {
            var propertyExpression = filterCriteria.PropertyToCompare.Split('.').Aggregate<string, MemberExpression>(null, (current, property) => Expression.Property(current ?? (parameter as Expression), property));

            Expression valueExpression;
            var constantExpression = Expression.Constant(filterCriteria.ValueToCompare);

            if (!filterCriteria.IsList)
            {
                valueExpression = Expression.Convert(constantExpression, propertyExpression.Type);
            }
            else
            {
                valueExpression = Expression.Call(typeof (Enumerable), "Any", new[] {typeof (string)},
                                                  propertyExpression, filterCriteria.Expression,
                                                  Expression.Constant(filterCriteria.ValueToCompare,
                                                                      typeof (string)));
            }

            Expression condition;
            switch (filterCriteria.FilterOperator)
            {
                case FilterOperator.IsEqualTo:
                    condition = Expression.Equal(propertyExpression, valueExpression);
                    break;
                case FilterOperator.IsNotEqualTo:
                    condition = Expression.NotEqual(propertyExpression, valueExpression);
                    break;
                case FilterOperator.IsGreaterThan:
                    condition = Expression.GreaterThan(propertyExpression, valueExpression);
                    break;
                case FilterOperator.IsGreaterThanOrEqualTo:
                    condition = Expression.GreaterThanOrEqual(propertyExpression, valueExpression);
                    break;
                case FilterOperator.IsLessThan:
                    condition = Expression.LessThan(propertyExpression, valueExpression);
                    break;
                case FilterOperator.IsLessThanOrEqualTo:
                    condition = Expression.LessThanOrEqual(propertyExpression, valueExpression);
                    break;
                case FilterOperator.Contains:
                    condition = Expression.Call(propertyExpression, typeof(string).GetMethod("Contains", new[] { typeof(string) }), valueExpression);
                    break;
                case FilterOperator.StartsWith:
                    condition = Expression.Call(propertyExpression, typeof(string).GetMethod("StartsWith", new[] { typeof(string) }), valueExpression);
                    break;
                case FilterOperator.EndsWith:
                    condition = Expression.Call(propertyExpression, typeof(string).GetMethod("EndsWith", new[] { typeof(string) }), valueExpression);
                    break;
                default:
                    condition = valueExpression;
                    break;
            }

            if (resultCondition != null)
            {
                switch (logicalOperator)
                {
                    case LogicalOperator.And:
                        resultCondition = Expression.AndAlso(resultCondition, condition);
                        break;
                    case LogicalOperator.Or:
                        resultCondition = Expression.OrElse(resultCondition, condition);
                        break;
                }
            }
            else
            {
                resultCondition = condition;
            }
        }
    }
    return resultCondition;
}

So verwende ich Ausdrücke:

var stories = new List<Story>();
var filters = new List<FilterCriteria>();
filter.Add(new FilterCriteria { ValueToCompare = "Test", PropertyToCompare = "Author", FilterOperator = FilterOperator.Contains });

Expression<Func<string, bool>> func  = t => t.Contains("Test");

filter.Add(new FilterCriteria { ValueToCompare = "Test", PropertyToCompare = "Contributors", FilterOperator = FilterOperator.Contains, Expression = func });

stories.Filter(filters, LogicalOperator.Or).ToList();

Aber nachdem ich diesen Code ausgeführt habe, erhalte ich diesen Fehler, den ich nicht beheben kann

Keine generische Methode 'Any' vom Typ 'System.Linq.Queryable' ist mit den übergebenen Typargumenten und Argumenten kompatibel. Wenn die Methode nicht generisch ist, sollten keine Typargumente angegeben werden. Beschreibung: Bei der Ausführung der aktuellen Webanforderung ist eine nicht behandelte Ausnahme aufgetreten. Bitte überprüfen Sie die Stack-Trace für weitere Informationen über den Fehler und wo es aus dem Code stammt.

Ausnahmedetails: System.InvalidOperationException: Keine generische Methode 'Any' für den Typ 'System.Linq.Queryable' ist mit den angegebenen Typargumenten und Argumenten kompatibel. Wenn die Methode nicht generisch ist, sollten keine Typargumente angegeben werden.

Quellfehler:

Zeile 184: {Zeile 185:
var overload = typeof (Abfragbar) .GetMethods (). Single (mi => mi.Name == "Beliebige" && mi.GetParameters (). Count () == 2); Linie 186:
Expression.Call (typeof (Queryable), "Beliebig", new [] {typeof (string)}, propertyExpression oder); Linie 187:
valueExpression = Expression.Call (typeof (Enumerable), "Beliebig", neu [] {typeof (string)}, propertyExpression oder Expression.Constant ("Test",

Akzeptierte Antwort

Sie rufen keine Any Methode in Ihrem Code auf.

Sie sollten Contains : Beispiel:

case FilterOperator.Contains:
    // if collection
    if (propertyExpression.Type.IsGenericType &&
        typeof(IEnumerable<>)
            .MakeGenericType(propertyExpression.Type.GetGenericArguments())
            .IsAssignableFrom(propertyExpression.Type))
    {
        // find AsQueryable method
        var toQueryable = typeof(Queryable).GetMethods()
            .Where(m => m.Name == "AsQueryable")
            .Single(m => m.IsGenericMethod)
            .MakeGenericMethod(typeof(string));

        // find Any method
        var method = typeof(Queryable).GetMethods()
            .Where(m => m.Name == "Any")
            .Single(m => m.GetParameters().Length == 2)
            .MakeGenericMethod(typeof(string));

        // make expression
        condition = Expression.Call(
            null, 
            method,
            Expression.Call(null, toQueryable, propertyExpression), 
            filterCriteria.Expression
        );
    }
    else
    {
        condition = Expression.Call(propertyExpression, typeof(string).GetMethod("Contains", new[] { typeof(string) }), valueExpression);
    }
    break;

Außerdem sollten Sie einen p Parameter ( Expression.Parameter(query.ElementType, "p") ) erstellt haben, ansonsten erhalten Sie die variable 'p' of type 'WpfApplication2.Story' referenced from scope '', but it is not defined Fehler variable 'p' of type 'WpfApplication2.Story' referenced from scope '', but it is not defined .

Sie können passieren parameter von Filter - Methode ToExpression Verfahren.



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum