我如何指定一个谓词的类型,我将不会知道,直到运行时? [英] How can I specify a predicate's type, which I won't know until runtime?
问题描述
IEnumerable< Car> getCars< TSortKey>(表达< Func< Car,TSortKey>> sort);
我使用 TSortKey
,因为我赢了' t知道将在运行时使用哪个属性,它可以是 x => x.Name
或 x => x.Make
哪些是字符串,但也可以是 x => x.History.Age
这是一个整数。
用户选择排序顺序,然后在交换机中设置排序谓词,调用该方法。
表达式< Func< Car,object>> sortPredicate;
switch(sortOption){
case SortOption.Name:sortPredicate = s => s.Name;打破;
case SortOption.Make:sortPredicate = s => s.Make;打破;
case SortOption.Age:sortPredicate = s => s.History.Age;打破;
default:sortPredicate = s => s.Name;打破;
}
var cars = repo.getCars(sortPredicate);
我在谓词中使用对象
直到运行时才会知道该类型。但是这会产生错误的SQL,并引发。
那么我该如何解决这个问题?
问题是 Expression< Func< T,object>>
生成额外的转换
对于值类型属性,EF不喜欢并抛出 NotSupportedException
。
而不是 OrderBy
,您可以在存储库类中使用以下帮助方法。它的作用是剥离转换
表达式,如果需要,并动态调用 Queryable.OrderBy
方法:
public static partial class EFExtensions
{
public static IOrderedQueryable< T> SortBy< T>(此IQueryable< T>源,表达式< Func< T,对象>> keySelector)
{
var body = keySelector.Body;
if(body.NodeType == ExpressionType.Convert)
body =((UnaryExpression)keySelector.Body).Operand;
var selector = Expression.Lambda(body,keySelector.Parameters);
var orderByCall = Expression.Call(
typeof(Queryable),OrderBy,new [] {typeof(T),body.Type},
source.Expression,Expression.Quote选择器));
return(IOrderedQueryable< T>)source.Provider.CreateQuery(orderByCall);
}
}
My repository method fetches stuff from the database. It accepts the sort order as an argument:
IEnumerable<Car> getCars<TSortKey>(Expression<Func<Car, TSortKey>> sort);
I use TSortKey
, because I won't know which property will be used until runtime, it could be x => x.Name
or x => x.Make
which are strings, but it could also be x => x.History.Age
which is an integer.
The user chooses the sort order, then I set up the sort predicate in a switch and call into that method.
Expression<Func<Car, object>> sortPredicate;
switch (sortOption) {
case SortOption.Name: sortPredicate = s => s.Name; break;
case SortOption.Make: sortPredicate = s => s.Make; break;
case SortOption.Age: sortPredicate = s => s.History.Age; break;
default: sortPredicate = s => s.Name; break;
}
var cars = repo.getCars(sortPredicate);
I use object
in the predicate, as I won't know the type until runtime. But that generates the wrong SQL, and throws.
So how can I fix this?
The problem is that Expression<Func<T, object>>
generates additional Convert
for value type properties, which EF does not like and throws NotSupportedException
.
Instead of OrderBy
, you can use the following helper method inside your repository class. What it does is stripping the Convert
expression if needed and calling the Queryable.OrderBy
method dynamically:
public static partial class EFExtensions
{
public static IOrderedQueryable<T> SortBy<T>(this IQueryable<T> source, Expression<Func<T, object>> keySelector)
{
var body = keySelector.Body;
if (body.NodeType == ExpressionType.Convert)
body = ((UnaryExpression)keySelector.Body).Operand;
var selector = Expression.Lambda(body, keySelector.Parameters);
var orderByCall = Expression.Call(
typeof(Queryable), "OrderBy", new[] { typeof(T), body.Type },
source.Expression, Expression.Quote(selector));
return (IOrderedQueryable<T>)source.Provider.CreateQuery(orderByCall);
}
}
这篇关于我如何指定一个谓词的类型,我将不会知道,直到运行时?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!