dynamische Sortierung in linq

c# c#-4.0 expression-trees lambda linq

Frage

Bitte beachten Sie dieses Szenario:

Ich habe eine Liste einer Klasse mit etwa 50 Feldern. Ich möchte eine Combobox haben, die der Benutzer auswählen kann, je nachdem, welche Feldliste sortiert wird. Zum Beispiel, wenn der Benutzer "F1" auswählt, sortiert nach "F1".

Ich möchte nicht mit if-else für alle Felder sortieren. Ich sehe dieses Thema:

Eine Gridview beim Datenbinding einer Sammlung oder Liste von Objekten sortieren

aber ich kann seine Antwort nicht verwenden. Wie kann ich Expression Tree für diesen Zweck verwenden?

Vielen Dank

Bearbeiten 1) :

Laut meiner Antwort @Thom Smith habe ich diesen Code geschrieben:

 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();
    }

aber es wurde nicht sortiert. wenn ich diesen Code auf diese Weise geschrieben habe:

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

es ist eine Art. Wo ist das Problem?

Akzeptierte Antwort

OrderBy führt keine direkte Sortierung durch. Es gibt eine Sequenz zurück, die bei der Auswertung sortiert wird. Dies geschieht normalerweise träge, dh bis es aufgezählt ist, tut es nichts . Ihr aktueller Code verwirft einfach diesen wichtigen Rückgabewert. Die Lösung ist einfach: Fange den Rückgabewert:

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

Hinweis: In ähnlicher Weise filtert das Anwenden von "Where" die vorhandenen Daten nicht: Sie gibt eine Sequenz zurück, die bei der Aufzählung gefiltert wird. Wenn du also filtern würdest, hättest du das ähnlich:

query = query.Where(...);

Beliebte Antwort

Hier ist die Methode, die ich dafür verwende:

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 ist nur eine Struktur mit einem Attribut und einer Richtung.

EDIT: Zusätzliche Erklärung.

Diese Methode stammt aus meiner DynamicOrderList Klasse, bei der es sich um eine Liste von OrderParameter Objekten handelt. Wenn Sie nur nach einem Feld sortieren müssen, können Sie es etwas vereinfachen:

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
    }
}

Dann benutze es wie:

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
    }
}

Und:

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


Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow