即使使用 $top 也强制执行 OData 项目的排序

Enforce ordering of OData items even when $top is used

我有一个DbSet<Items>collection。

主键是一个 Guid。我不想按这个主键排序。我想通过名为 "Order".

的 editable 十进制 属性 进行订购

我的代码非常简单,在用户将“$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(),我试过了有两个 AsQueryables 等

这个table中会有很多项,所以需要通过IQueryable(枚举所有通过 IEnumerable 在网络服务器上的项目在这里不是一个选项。

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

1.) 我可以做些什么来让我的 Order 属性 订购成为这里的默认行为吗?

2.) 或者失败了,是否有任何方法可以让 WebApi / OData 认为指定了自定义的“$orderby=Order”子句?

您可以在控制器中手动调用 odata。这应该创建正确排序的 IQueryable,然后应用 $top 和任何其他 odata,如 $filter 和 $skip。现在您不必 return 导致问题的 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 documentation 中找到更多信息。

要覆盖默认排序顺序,您需要将 EnableQueryAttribute 的 属性 EnsureStableOrdering 设置为 false,如 describe here:

A true value indicates the original query should be modified when necessary to guarantee a stable sort order. A false value indicates the sort order can be considered stable without modifying the query. Query providers that ensure a stable sort order should set this value to false. The default value is true.

所以在您的代码中,像这样更改操作属性:

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