首页 > 解决方案 > 处理请求时发生未处理的异常。(asp.net 上的 Rest api 排序)

问题描述

InvalidOperationException:无法翻译 LINQ 表达式“DbSet().OrderBy(s => s.GetType().GetProperty(__sort_by_0).GetValue(s))”。以可翻译的形式重写查询,或通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用显式切换到客户端评估。有关详细信息,请参阅https://go.microsoft.com/fwlink/?linkid=2101038

当我尝试按属性对我的 rest api 进行排序时,会发生此错误。在此处输入图像描述

标签: c#apirestsortingsql-order-by

解决方案


有人在评论中链接了以前的答案,这让我不确定我是否应该回答这个问题,但是,它已经写好了。:)

基本上动态排序比您尝试做的要复杂一些。那GetType(), GetProperty(), 等反射代码不能在数据库中执行。

你基本上有两个选择:

1) 使用动态 Linq 包

使用System.Linq.Dynamic.Core包(请参阅文档),您可以提供对实体成员的字符串引用,并将其转换为表达式。

这意味着你可以简单地写这个:

_context.SwiftTransfers.OrderBy(sort_by).ToListAsync();

2) 使用自定义解决方案将字符串转换为表达式

您可以自己构建表达式。例如,以下方法支持IQueryable根据提供的字符串成员名称(可以引用具有“用户/名称/名字”模式的嵌套属性)对 应用多个升序或降序:

static IQueryable<T> ApplyOrdering(IQueryable<T> query, string propertyPath, bool isAscending = true, bool firstOrdering = true)
{
    var param = Expression.Parameter(typeof(T), "p");
    var member = (MemberExpression)propertyPath.Split('/').Aggregate((Expression)param, Expression.Property);
    var exp = Expression.Lambda(member, param);
    string methodName = isAscending switch
    {
        true => firstOrdering ? "OrderBy" : "ThenBy",
        false => firstOrdering ? "OrderByDescending" : "ThenByDescending"
    };
    Type[] types = new Type[] { query.ElementType, exp.Body.Type };
    var orderByExpression = Expression.Call(typeof(Queryable), methodName, types, query.Expression, exp);
    return query.Provider.CreateQuery<T>(orderByExpression);
}

// Then call it like this:
ApplyOrdering(_context.SwiftTransfers.AsQueryable(), sort_by).ToListAsync();

这可以用作扩展方法IQueryable以更舒适地访问它。

提示

  • 如果您想实现符合标准的排序/过滤方式,您可以查看OData。它有现成的包,你可以在 ASP.NET Core 的端点上应用。不过,我个人不太喜欢他们的实施建议,因此我通常手动实施符合 OData 的过滤和排序。

  • 如果您使用更改数据形状的 DTO,并且客户端将根据 DTO 向您发送排序参数,您可能会遇到给定属性名称在您尝试排序的实际实体上不存在的问题. 但是,如果您使用 AutoMapper 进行映射,并且如果您映射 via ProjectTo<TDto>(),则会自动将表达式转换回来,以便它们引用正确的实体属性。因此,您不必手动进行属性名称映射。


推荐阅读