tri dynamique dans linq

c# c#-4.0 expression-trees lambda linq

Question

veuillez considérer ce scénario:

J'ai une liste d'une classe d'environ 50 champs.Je veux avoir une liste déroulante que l'utilisateur peut sélectionner en fonction de la liste de champs qui va trier.

Je ne veux pas trier avec if-else pour tous les champs.Je vois ce sujet:

Tri d'une grille lors de la liaison de données d'une collection ou d'une liste d'objets

mais je ne peux pas utiliser sa réponse. Comment puis-je utiliser Expression Tree à cette fin?

Merci

Modifier 1) :

Selon la réponse de @Thom Smith, j’ai écrit ce code:

 using (NorthwindModel1.NorthwindEntities2 ent = new NorthwindModel1.NorthwindEntities2())
    {
        var query = from o in ent.Orders
                    where o.OrderID < 10257
                    select o;

        query.OrderBy("CustomerID", SortDirection.Ascending);

        GridView1.DataSource = query;
        GridView1.DataBind();
    }

mais ce n'était pas trié. si j'ai écrit ce code de cette façon:

GridView1.DataSource = query.OrderBy(o=>o.CustomerID);

c'est en quelque sorte. où est le problème?

Réponse acceptée

OrderBy ne fait pas de tri sur place. Il retourne une séquence qui, une fois évaluée, sera triée. Ceci est généralement fait paresseusement, ce qui signifie: jusqu'à ce qu'il soit énuméré, il ne fait rien . Votre code actuel ignore simplement cette valeur de retour essentielle. Le correctif est simple: attrapez la valeur de retour:

query = query.OrderBy("CustomerID", SortDirection.Ascending);

Remarque: de la même façon, l'application "Où" ne filtre pas les données existantes: elle renvoie une séquence filtrée lors de l'énumération . Donc, si vous filtriez, vous auriez le même résultat:

query = query.Where(...);

Réponse populaire

Voici la méthode que j'utilise pour cela:

private IQueryable<T> OrderQuery<T>(IQueryable<T> query, OrderParameter orderBy)
{
    string orderMethodName = orderBy.Direction == SortDirection.Ascending ? "OrderBy" : "OrderByDescending";
    Type t = typeof(T);

    var param = Expression.Parameter(t, "shipment");
    var property = t.GetProperty(orderBy.Attribute);

    /* We can't just call OrderBy[Descending] with an Expression
     * parameter because the second type argument to OrderBy is not
     * known at compile-time.
     */
    return query.Provider.CreateQuery<T>(
        Expression.Call(
            typeof(Queryable),
            orderMethodName,
            new Type[] { t, property.PropertyType },
            query.Expression,
            Expression.Quote(
                Expression.Lambda(
                    Expression.Property(param, property),
                    param))
        ));
}

OrderParameter est juste une structure avec un attribut et une direction.

EDIT: Explication supplémentaire.

Cette méthode provient de ma classe DynamicOrderList , qui est une liste d'objets OrderParameter . Si vous n'avez besoin que de trier un champ, vous pouvez le simplifier un peu:

private IQueryable<T> OrderByDynamic<T>(this IQueryable<T> query, string attribute, SortDirection direction)
{
    try
    {
        string orderMethodName = direction == SortDirection.Ascending ? "OrderBy" : "OrderByDescending";
        Type t = typeof(T);

        var param = Expression.Parameter(t);
        var property = t.GetProperty(attribute);

        return query.Provider.CreateQuery<T>(
            Expression.Call(
                typeof(Queryable),
                orderMethodName,
                new Type[] { t, property.PropertyType },
                query.Expression,
                Expression.Quote(
                    Expression.Lambda(
                        Expression.Property(param, property),
                        param))
            ));
    }
    catch (Exception) // Probably invalid input, you can catch specifics if you want
    {
        return query; // Return unsorted query
    }
}

Alors utilisez-le comme:

myQuery = myQuery.OrderByDynamic("name", SortDirection.Ascending);

EDIT 2:

public IQueryable<T> OrderBy<T>(this IQueryable<T> query, string attribute, SortDirection direction)
{
    return ApplyOrdering(query, attribute, direction, "OrderBy");
}

public IQueryable<T> ThenBy<T>(this IQueryable<T> query, string attribute, SortDirection direction)
{
    return ApplyOrdering(query, attribute, direction, "ThenBy");
}

private IQueryable<T> ApplyOrdering<T>(IQueryable<T> query, string attribute, SortDirection direction, string orderMethodName)
{
    try
    {
        if (direction == SortDirection.Descending) orderMethodName += "Descending";

        Type t = typeof(T);

        var param = Expression.Parameter(t);
        var property = t.GetProperty(attribute);

        return query.Provider.CreateQuery<T>(
            Expression.Call(
                typeof(Queryable),
                orderMethodName,
                new Type[] { t, property.PropertyType },
                query.Expression,
                Expression.Quote(
                    Expression.Lambda(
                        Expression.Property(param, property),
                        param))
            ));
    }
    catch (Exception) // Probably invalid input, you can catch specifics if you want
    {
        return query; // Return unsorted query
    }
}

Et:

myQuery=myQuery.OrderBy("name", SortDirection.Ascending).ThenBy("date", SortDirection.Descending);


Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow