C# 如何指定谓词';s型,我赢了';直到运行时我才知道?
我的存储库方法从数据库中获取内容。它接受排序顺序作为参数:C# 如何指定谓词';s型,我赢了';直到运行时我才知道?,c#,entity-framework,linq,lambda,C#,Entity Framework,Linq,Lambda,我的存储库方法从数据库中获取内容。它接受排序顺序作为参数: IEnumerable<Car> getCars<TSortKey>(Expression<Func<Car, TSortKey>> sort); 我在谓词中使用object,因为直到运行时我才知道类型。但这会生成错误的SQL,并抛出 那么我该如何解决这个问题呢?问题是表达式为值类型属性生成额外的转换,EF不喜欢这些属性,并抛出NotSupportedException 您可以在存储库类
IEnumerable<Car> getCars<TSortKey>(Expression<Func<Car, TSortKey>> sort);
我在谓词中使用object
,因为直到运行时我才知道类型。但这会生成错误的SQL,并抛出
那么我该如何解决这个问题呢?问题是
表达式
为值类型属性生成额外的转换
,EF不喜欢这些属性,并抛出NotSupportedException
您可以在存储库类中使用以下helper方法,而不是OrderBy
。如果需要,它将剥离Convert
表达式,并动态调用Queryable.OrderBy
方法:
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);
}
}
公共静态部分类扩展
{
公共静态IOrderedQueryable排序方式(此IQueryable源、表达式键选择器)
{
var body=keySelector.body;
if(body.NodeType==ExpressionType.Convert)
body=((UnaryExpression)keySelector.body).操作数;
var selector=Expression.Lambda(body,keySelector.Parameters);
var orderByCall=Expression.Call(
typeof(Queryable),“OrderBy”,new[]{typeof(T),body.Type},
source.Expression,Expression.Quote(选择器));
返回(IOrderedQueryable)source.Provider.CreateQuery(orderByCall);
}
}
可能的解决方案:我可以将方法调用移动到每个开关案例中,但这会变得非常混乱。e、 g.case-SortOption.Name:cars=repo.getCars(x=>x.Name);中断代码>我相当肯定您可能的解决方案是最好的。另一种可能是将您的排序
枚举传递到repo中,并在适当的位置构建正确的lamda。@Jamiec是的,我现在正在用“混乱”的方式,但它变得非常混乱,因为这只是我真实代码的一小部分。我希望我能以某种方式重写lambda,改为使用泛型类型。您可以考虑使用反射来创建表达式函数,创建getCars的泛型方法并调用它。如果你需要更多的帮助,我可以写一个答案怎么办。这真的很棒。我还添加了一个SortByDescending
方法。像这样重写表达式和反射一样“慢”吗?我认为不是,因为您不是在查询类型和元数据,而是在创建新的内容。是吗?我相信你能做到!尽管您也可以将bool descending
参数添加到上述方法中,并在内部使用“OrderBy”+(descending?“descending”:“)
),但在这种情况下重写lambda与反射不同,因为您是在重用已构建的表达式(body或body.operator)。关于表达式.Call
,这正是Queryable
方法所做的-是的,这很有意义。再次感谢。
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);
}
}