【问题标题】:Enforce ordering of OData items even when $top is used即使使用 $top 也强制对 OData 项目进行排序
【发布时间】:2015-08-29 03:46:50
【问题描述】:

我有一个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(),我尝试使用两个AsQueryables 等等。

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

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

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

2.) 否则,是否有办法欺骗 WebApi / OData 认为已指定自定义“$orderby=Order”子句?

【问题讨论】:

    标签: linq entity-framework asp.net-web-api odata iqueryable


    【解决方案1】:

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

    真值表示应该修改原始查询 有必要保证稳定的排序顺序。错误值表示 在不修改查询的情况下,排序顺序可以被认为是稳定的。 确保稳定排序顺序的查询提供程序应设置此值 为假。默认值为 true。

    所以在你的代码中,像这样改变 action 属性:

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

    【讨论】:

    • 很奇怪;当我在周五发布此内容时,我尝试了几次(也进行了完全清理/重建),但它根本不起作用。今天它奏效了。也许 Visual Studio Web 服务器需要回收?
    • 嗨!也许是的...有时我必须重新启动 VS IIS Express 实例才能刷新。
    【解决方案2】:

    您可以在控制器中手动调用 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 documentation找到。

    【讨论】:

    • 赞成有趣的解决方案。上述属性的事情今天开始为我工作,但这看起来是一个很好的备份,以防其他人开始行动。
    猜你喜欢
    • 1970-01-01
    • 2014-06-16
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    • 1970-01-01
    • 2023-02-16
    • 2010-09-10
    • 2023-04-03
    相关资源
    最近更新 更多