强制对 OData 项进行排序,即使使用了 $top



我有一个DbSet<Items>集合。

主键是 Guid。 我不想按此主键排序。 我想按名为"Order"的可编辑十进制属性排序。

我拥有的代码非常简单,在用户将"$top"参数放入请求之前,它运行良好:

public class ItemsController : ApiController
{
    protected DbContext ctx = // ...
    // GET api/documents
    [EnableQuery()]
    public IQueryable<Item> Get()
{
    return ctx.Items.OrderBy(o => o.Order).AsQueryable();
}

当用户将"$top"放入查询字符串时,顺序会全部搞砸(它可能会强制由主键完成排序,以获得一致的分页结果 - 但是,在我的情况下,这会产生相反的效果,它阻止我获得一致的分页结果)。

我尝试将.AsQueryable()移动到查询的早期(在 .OrderBy(...) 子句之前),我尝试过没有.AsQueryable(),我尝试过使用两个 AsQueryable 等。

此表中将有很多项目,因此需要通过IQueryable来完成(通过IEnumerable枚举 Web 服务器上的所有项目在这里不是一个选项)。

到目前为止,唯一有效的方法是从客户端传入"$orderby=Order",但我不想强迫这样做(似乎很容易被遗忘)。

1.) 我能做些什么来使我的 Order 属性排序成为这里的默认行为?

2.)或者做不到这一点,是否有任何方法可以欺骗WebApi/OData,使其认为指定了自定义的"$orderby=Order"子句?

要覆盖默认排序顺序,您需要将属性 EnsureStableOrder of EnableQueryAttribute 设置为 false,如下所述:

true 值指示应在以下情况下修改原始查询 是保证稳定排序顺序所必需的。假值表示 在不修改查询的情况下,可以认为排序顺序是稳定的。 确保排序顺序稳定的查询提供程序应设置此值 到假。默认值为 true。

因此,在您的代码中,更改操作属性,如下所示:

// GET api/documents
[EnableQuery(EnsureStableOrdering = false)]
public IQueryable<Item> Get()
{
    return ctx.Items.OrderBy(o => o.Order).AsQueryable();
}

您可以在控制器中手动调用 odata。这应该创建正确排序的 IQueryable,然后应用 $top 和任何其他 odata,如 $filter 和 $skip。现在,您不必返回导致问题的 IQueryable,因为实际查询稍后在管道中执行。

public class ItemsController : ApiController
{
    protected DbContext ctx = // ...
    public IEnumerable<Item> Get(ODataQueryOptions<Item> odata)
    {
        var collection = ctx.Items.OrderBy(o => o.Order);
        if (odata == null)
        {
            //return a default max size of 100
            return collection.Take(100).ToList();
        }
        var results = odata.ApplyTo(collection.AsQueryable()) as List<Item>;
        //still provide a max incase the $top wasn't specified.
        //you could check the odata to see if $top is there or not.
        return results.Take(100);
    }
}

有关详细信息,请参阅 WebApi 文档。

相关内容

  • 没有找到相关文章