score:146
i would offer this alternative to what everyone else has posted.
system.reflection.propertyinfo prop = typeof(yourtype).getproperty("propertyname");
query = query.orderby(x => prop.getvalue(x, null));
this avoids repeated calls to the reflection api for obtaining the property. now the only repeated call is obtaining the value.
however
i would advocate using a propertydescriptor
instead, as this will allow for custom typedescriptor
s to be assigned to your type, making it possible to have lightweight operations for retrieving properties and values. in the absence of a custom descriptor it will fall back to reflection anyhow.
propertydescriptor prop = typedescriptor.getproperties(typeof(yourtype)).find("propertyname");
query = query.orderby(x => prop.getvalue(x));
as for speeding it up, check out marc gravel's hyperdescriptor
project on codeproject. i've used this with great success; it's a life saver for high-performance data binding and dynamic property operations on business objects.
score:0
i think we can use a powerful tool name expression an in this case use it as an extension method as follows:
public static iorderedqueryable<t> orderby<t>(this iqueryable<t> source, string ordering, bool descending)
{
var type = typeof(t);
var property = type.getproperty(ordering);
var parameter = expression.parameter(type, "p");
var propertyaccess = expression.makememberaccess(parameter, property);
var orderbyexp = expression.lambda(propertyaccess, parameter);
methodcallexpression resultexp =
expression.call(typeof(queryable), (descending ? "orderbydescending" : "orderby"),
new type[] { type, property.propertytype }, source.expression, expression.quote(orderbyexp));
return (iorderedqueryable<t>)source.provider.createquery<t>(resultexp);
}
score:1
also dynamic expressions can solve this problem. you can use string-based queries through linq expressions that could have been dynamically constructed at run-time.
var query = query
.where("category.categoryname == @0 and orders.count >= @1", "book", 10)
.orderby("productid")
.select("new(productname as name, price)");
score:2
reflection is the answer!
typeof(yourtype).getproperty("productid").getvalue(theinstance);
there's lots of things you can do to cache the reflected propertyinfo, check for bad strings, write your query comparison function, etc., but at its heart, this is what you do.
score:2
more productive than reflection extension to dynamic order items:
public static class dynamicextentions
{
public static object getpropertydynamic<tobj>(this tobj self, string propertyname) where tobj : class
{
var param = expression.parameter(typeof(tobj), "value");
var getter = expression.property(param, propertyname);
var boxer = expression.typeas(getter, typeof(object));
var getpropvalue = expression.lambda<func<tobj, object>>(boxer, param).compile();
return getpropvalue(self);
}
}
example:
var ordered = items.orderby(x => x.getpropertydynamic("productid"));
also you may need to cache complied lambas(e.g. in dictionary<>)
score:2
warning ⚠
you just can use reflection
in case that data is in-memory. otherwise, you will see some error like below when you work with linq-2-ef, linq-2-sql, etc.
linq to entities does not recognize the method 'system.object getvalue(system.object)' method and this method cannot be translated into a store expression.
why ⁉
because when you write code to provide a query to linq query provider
. it is first translated into an sql statement and then executed on the database server.
(see image below, from https://www.tutorialsteacher.com/linq/linq-expression)
solution ✅
by using expression tree, you can write a generic method like this
public static ienumerable<t> orderdynamic<t>(ienumerable<t> data, string proptoorder)
{
var param = expression.parameter(typeof(t));
var memberaccess = expression.property(param, proptoorder);
var convertedmemberaccess = expression.convert(memberaccess, typeof(object));
var orderpredicate = expression.lambda<func<t, object>>(convertedmemberaccess, param);
return data.asqueryable().orderby(orderpredicate).toarray();
}
and use it like this
var result = orderdynamic<student>(yourquery, "studentname"); // string property
or
var result = orderdynamic<student>(yourquery, "age"); // int property
and it's also working with in-memory by converting your data into iqueryable<telement>
in your generic method return statement like this
return data.asqueryable().orderby(orderpredicate).toarray();
see the image below to know more in-depth.
score:5
query = query.orderby(x => x.gettype().getproperty("productid").getvalue(x, null));
trying to recall exact syntax off the top of my head but i think that is correct.
score:13
yes, i don't think there's another way than reflection.
example:
query = query.orderby(x => x.gettype().getproperty("productid").getvalue(x, null));
score:51
i liked the answer from @mark powell, but as @shuberfu said, it gives the error linq to entities only supports casting edm primitive or enumeration types
.
removing var propasobject = expression.convert(property, typeof(object));
didn't work with properties that were value types, such as integer, as it wouldn't implicitly box the int to object.
using ideas from kristofer andersson and marc gravell i found a way to construct the queryable function using the property name and have it still work with entity framework. i also included an optional icomparer parameter. caution: the icomparer parameter does not work with entity framework and should be left out if using linq to sql.
the following works with entity framework and linq to sql:
query = query.orderby("productid");
and @simon scheurer this also works:
query = query.orderby("productcategory.categoryid");
and if you are not using entity framework or linq to sql, this works:
query = query.orderby("productcategory", comparer);
here is the code:
public static class iqueryableextensions
{
public static iorderedqueryable<t> orderby<t>(this iqueryable<t> query, string propertyname, icomparer<object> comparer = null)
{
return callorderedqueryable(query, "orderby", propertyname, comparer);
}
public static iorderedqueryable<t> orderbydescending<t>(this iqueryable<t> query, string propertyname, icomparer<object> comparer = null)
{
return callorderedqueryable(query, "orderbydescending", propertyname, comparer);
}
public static iorderedqueryable<t> thenby<t>(this iorderedqueryable<t> query, string propertyname, icomparer<object> comparer = null)
{
return callorderedqueryable(query, "thenby", propertyname, comparer);
}
public static iorderedqueryable<t> thenbydescending<t>(this iorderedqueryable<t> query, string propertyname, icomparer<object> comparer = null)
{
return callorderedqueryable(query, "thenbydescending", propertyname, comparer);
}
/// <summary>
/// builds the queryable functions using a tsource property name.
/// </summary>
public static iorderedqueryable<t> callorderedqueryable<t>(this iqueryable<t> query, string methodname, string propertyname,
icomparer<object> comparer = null)
{
var param = expression.parameter(typeof(t), "x");
var body = propertyname.split('.').aggregate<string, expression>(param, expression.propertyorfield);
return comparer != null
? (iorderedqueryable<t>)query.provider.createquery(
expression.call(
typeof(queryable),
methodname,
new[] { typeof(t), body.type },
query.expression,
expression.lambda(body, param),
expression.constant(comparer)
)
)
: (iorderedqueryable<t>)query.provider.createquery(
expression.call(
typeof(queryable),
methodname,
new[] { typeof(t), body.type },
query.expression,
expression.lambda(body, param)
)
);
}
}
score:90
i'm a little late to the party, however, i hope this can be of some help.
the problem with using reflection is that the resulting expression tree will almost certainly not be supported by any linq providers other than the internal .net provider. this is fine for internal collections, however this will not work where the sorting is to be done at source (be that sql, mongodb, etc.) prior to pagination.
the code sample below provides iqueryable extention methods for orderby and orderbydescending, and can be used like so:
query = query.orderby("productid");
extension method:
public static class iqueryableextensions
{
public static iorderedqueryable<t> orderby<t>(this iqueryable<t> source, string propertyname)
{
return source.orderby(tolambda<t>(propertyname));
}
public static iorderedqueryable<t> orderbydescending<t>(this iqueryable<t> source, string propertyname)
{
return source.orderbydescending(tolambda<t>(propertyname));
}
private static expression<func<t, object>> tolambda<t>(string propertyname)
{
var parameter = expression.parameter(typeof(t));
var property = expression.property(parameter, propertyname);
var propasobject = expression.convert(property, typeof(object));
return expression.lambda<func<t, object>>(propasobject, parameter);
}
}
regards, mark.
Source: stackoverflow.com
Related Query
- C# - code to order by a property using the property name as a string
- Order a list by a string value with the same name as the property
- Select a model property using a lambda and not a string property name
- linq orderby using property name string
- Sorting using property name as string
- Can I parameterize the property name of a PropertyExpression using LINQ Expressions?
- Select property by string name using LINQ
- Using Linq, order objects by some property and select the first 2 objects
- LINQ query in C# using string on the fly to ORDER data
- Find a string in the list and change value of another property using linq (complicated)
- Linq select a single field using a string containing the name of the field
- Ordering by ICollection property using its name as string with Dynamic Linq Library
- A field or property with the name 'OrderID' was not found on the selected data source
- Using string in place of property name (LINQ)
- Linq to sql order by a string that is not a property of the object
- Order By String which matches property name gives Null Reference
- How to get property name desending order in every record using Linq
- How do I find the text within a div in the source of a web page using C#
- How do I apply OrderBy on an IQueryable using a string column name within a generic extension method?
- A specified Include path is not valid. The EntityType does not declare a navigation property with the name *
- How to convert a List<T> into a comma-separated list, using the class's Id property as the value
- Using LINQ, can I verify a property has the same value for all objects?
- EF Query using .Contains() and .ToLowerInvariant() Results in no matches when match is found at the end of a string
- Change the property of objects in a List using LINQ
- Using LINQ to parse the numbers from a string
- Is order of the predicate important when using LINQ?
- LINQ group by query using reflected property name
- How to check if all of the elements in a list return true for a property using Linq?
- Get the number of distinct property values in List<T> using LINQ in C#
- Linq - group by using the elements inside an array property
More Query from same tag
- DataGridView listing selected item from ListBox
- Left join with OrderBy in LINQ
- return the first longest string consisting of n consecutive strings taken in the array in c#
- Single table with data from multiple database tables
- LINQ and Null Coallescing
- Linq filter out rows with null or string.empty
- Returning an object from a LINQ query without casting it to a list
- Retrieving binary back to image and from database and save into a folder using WPF
- linq mysql query into int array
- How to sort stock months using linq C#
- how to get the value using linq query C#
- LINQ Grouping dynamically
- in C#, how do I order items in a list where the "largest" values are in the middle of the list
- Hitting the 2100 parameter limit (SQL Server) when using Contains()
- Linq - Grouping by date and selecting count
- Convert List<List<string>> to List<string>
- Linq Query not returning previous 6 months
- How can I control all of these situations that I want to find no reservation at that selected checkin and checkout time?
- check List <int> A contains elements from list B, with repeated values
- convert linq results of decimal to ObservableCollection<string>
- Cast System.Data.Linq.Table<T> to custom class
- How to pass an async method as an action?
- Directory.EnumerateFiles method: How to enumerate files in specified subdirectories?
- How to query names from a record with multiple IDs in LINQ
- How do I flatten a List<IList>()?
- How to dynamically instantiate 3 different classes into the same variable name, linq2sql c#
- Query MongoDb from C# - using Linq .Any() with predicate
- Better or optimized way to filter customer records by 3 dropdown filters
- Sequence contains no elements error with linq
- Create Numeric Contain Expression with reflection in c#?