Reputation: 650
Let's assume that I have two classes:
class person
{
int ID
string name
Address address
}
class address
{
int ID
string street
string country
}
These classes are more or less given, they are mapped via nHibernate to be honest :)
In a grid (datatables.net as base) I would like to have a type-independent sorting.
Therefore I created a lambda expression:
var param = Expression.Parameter(typeof(T), typeof(T).Name);
var sortExpression = Expression.Lambda<Func<T, object>>
(Expression.Convert(Expression.Property(param, "Property to sort"), typeof(object)), param);
If I pass Person as Type T and replace the "Property to sort" with "name" it works fine (creates a correct lambda). If the Property to sort is "address.street" it won't work, throw me the following error:
Property 'address.street' is not defined for type 'person'
I see only one solution so far, but not clear enough... I would try to split the string which contains the Property-Name (split by .)
Can anyone give a better solution? I need to add the sortExpression to an IQueryable object query.OrderBy(sortExpression)
.
Not sure if my title is clear, please go ahead and correct it.
Thanks in advance.
Upvotes: 10
Views: 7716
Reputation: 1
Try this one
public static IQueryable<T> SortIQueryable<T>(IQueryable<T> data, string fieldName, string sortOrder)
{
if (string.IsNullOrWhiteSpace(fieldName)) return data;
if (string.IsNullOrWhiteSpace(sortOrder)) return data;
var param = Expression.Parameter(typeof(T), "i");
MemberExpression property = null;
string[] fieldNames = fieldName.Split('.');
foreach (string filed in fieldNames)
{
if (property == null)
{
property = Expression.Property(param, filed);
}
else
{
property = Expression.Property(property, filed);
}
}
Expression conversion = Expression.Convert(property, typeof(object));//Expression.Property(param, fieldName)
var mySortExpression = Expression.Lambda<Func<T, object>>(conversion, param);
return (sortOrder == "desc") ? data.OrderByDescending(mySortExpression)
: data.OrderBy(mySortExpression);
}
Upvotes: 0
Reputation: 15664
Here's a more generic version of LukLed's answer:
protected MemberExpression NestedExpressionProperty(Expression expression, string propertyName)
{
string[] parts = propertyName.Split('.');
int partsL = parts.Length;
return (partsL > 1)
?
Expression.Property(
NestedExpressionProperty(
expression,
parts.Take(partsL - 1)
.Aggregate((a, i) => a + "." + i)
),
parts[partsL - 1])
:
Expression.Property(expression, propertyName);
}
You can use it like this:
var paramExpression = Expression.Parameter(this.type, "val");
var firstProp = NestedExpressionProperty(paramExpression,"address.street");
Upvotes: 5
Reputation: 126547
It seems to me you're trying to rewrite Microsoft DynamicQuery. Why not just use that instead?
Here's an example:
IQueryable<Foo> myQuery = GetHibernateQuery();
myQuery = myQuery.OrderBy("address.street");
Upvotes: 2
Reputation: 31842
What is not clear?
You have to split it and then use:
Expression.Property(Expression.Property(param, "address"), "street")
Upvotes: 13