我如何指定一个谓词的类型,我将不会知道,直到运行时? [英] How can I specify a predicate's type, which I won't know until runtime?

查看:91
本文介绍了我如何指定一个谓词的类型,我将不会知道,直到运行时?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的存储库方法从数据库中获取东西。它接受排序顺序作为参数:

  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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆