please consider this scenario:
I have a list of a class with about 50 fields.I want to have a Combobox that user can select according to what field list will sort.For example if user select "F1" list sort according to "F1".
I don't want to sort with if-else
for every fields.I see this topic :
Sorting a gridview when databinding a collection or list of objects
but I can't use of it's answer. How I can use Expression Tree
for this purpose?
thanks
Edit 1) :
According to dear @Thom Smith answer I wrote this 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();
}
but it was not sorted. if I wrote that code in this way:
GridView1.DataSource = query.OrderBy(o=>o.CustomerID);
it being sort. where is the problem?
OrderBy does not do an in-place sort. It returns a sequence which when evaluated will be sorted. This is usually done lazily, meaning: until it is enumerated, it does nothing. Your current code simply discards this all-important return value. The fix is simple: catch the return value:
query = query.OrderBy("CustomerID", SortDirection.Ascending);
Note: similarly, applying "Where" doesn't filter the existing data: it returns a sequence that when enumerated is filtered. So if you were filtering you'd have the similar:
query = query.Where(...);
Here's the method I use for this:
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
is just a struct with an attribute and direction.
EDIT: Additional explanation.
This method is from my DynamicOrderList
class, which is a list of OrderParameter
objects. If all you need is sorting by one field, then you can simplify it a bit:
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
}
}
Then use it like:
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
}
}
And:
myQuery=myQuery.OrderBy("name", SortDirection.Ascending).ThenBy("date", SortDirection.Descending);
Check out this link Multiple Field Sorting by Field Names Using Linq
Hope it may help to accomplish what you need.
Here's my hot take, using Enumerable
+Reflection instead of query:
list.OrderBy(x => {
var prop = x.GetType().GetProperty(sortFieldName);
return prop.GetValue(x);
});
if (!isSortAsc) list.Reverse();
Hope it will be helpful. It worked for Me to filter C# List Dynamically
string jtSorting = "ContactName";
DashboardModel Sup = new DashboardModel();
List<Applicant> lstSup = Sup.GetonBoard();
lstSup = lstSup.AsQueryable().SortBy(jtSorting).ToList();