Podobała mi się odpowiedź od @Mark Powell, ale jako @ShuberFu powiedział, daje błąd LINQ to Entities only supports casting EDM primitive or enumeration types
.
Usunięcie var propAsObject = Expression.Convert(property, typeof(object));
nie działało z właściwościami, które były typami wartości, na przykład liczbą całkowitą, ponieważ nie wstawiałby niejawnie int do obiektu.
Korzystanie z pomysłów od Kristofer Andersson i Marc Gravell Znalazłem sposób na skonstruowanie funkcji Queryable za pomocą nazwy właściwości i nadal działa z Entity Framework. Dodałem również opcjonalny parametr IComparer. Ostrzeżenie: Parametr IComparer nie działa z Entity Framework i powinien zostać pominięty, jeśli używa się Linq do Sql.
następujące prace z Entity Framework i LINQ to SQL:
query = query.OrderBy("ProductId");
I @Simon Scheurer Działa to również:
query = query.OrderBy("ProductCategory.CategoryId");
A jeśli nie używają Entity Framework lub LINQ do SQL to działa :
query = query.OrderBy("ProductCategory", comparer);
Oto kod:
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)
)
);
}
}
Myślę, że musiałbyś użyć odbicia, i nie jestem pewien, czy możesz użyć odbicia w wyrażeniu lambda ... no, prawie na pewno nie w Linq na SQL, ale może podczas używania Linq na liście lub coś. – CodeRedick
@Telos: Nie ma powodu, dla którego nie można używać odbicia (ani żadnego innego API) w lambda. To, czy zadziała, czy kod zostanie oceniony jako wyrażenie i przetłumaczone na coś innego (jak LINQ-SQL, jak sugerujesz), jest zupełnie inne. –
Dlatego wysłałem komentarz zamiast odpowiedzi. ;) Najczęściej używane do Linq2SQL ... – CodeRedick