ordinamento dinamico in linq

c# c#-4.0 expression-trees lambda linq

Domanda

per favore considera questo scenario:

Ho una lista di una classe con circa 50 campi. Voglio avere un Combobox che l'utente può selezionare in base a quale elenco di campi sarà ordinato. Ad esempio, se l'utente seleziona la lista "F1" ordina secondo "F1".

Non voglio ordinare con if-else per ogni campo. Vedo questo argomento:

Ordinamento di una vista a griglia quando si associa una raccolta o un elenco di oggetti

ma non posso usare la sua risposta. Come posso usare Expression Tree per questo scopo?

Grazie

Modifica 1) :

Secondo la cara risposta @Thom Smith ho scritto questo codice:

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

ma non è stato ordinato. se ho scritto quel codice in questo modo:

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

essendo sorta. dov'è il problema?

Risposta accettata

OrderBy non esegue un ordinamento sul posto. Restituisce una sequenza che, una volta valutata, verrà ordinata. Questo di solito viene fatto pigramente, cioè: finché non viene enumerato, non fa nulla . Il tuo codice attuale semplicemente scarta questo importantissimo valore di ritorno. La correzione è semplice: prendi il valore di ritorno:

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

Nota: analogamente, l'applicazione "Dove" non filtra i dati esistenti: restituisce una sequenza che quando viene enumerata viene filtrata. Quindi se stavi filtrando avresti il ​​simile:

query = query.Where(...);

Risposta popolare

Ecco il metodo che uso per questo:

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 è solo una struttura con un attributo e una direzione.

EDIT: spiegazione aggiuntiva.

Questo metodo proviene dalla mia classe DynamicOrderList , che è un elenco di oggetti OrderParameter . Se tutto ciò di cui hai bisogno è l'ordinamento per un campo, puoi semplificarlo un po ':

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

Quindi usarlo come:

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

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

E:

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


Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché