【问题标题】:Simple OData Client - create OrderBy expression at runtime?简单的 OData 客户端 - 在运行时创建 OrderBy 表达式?
【发布时间】:2021-05-01 15:29:39
【问题描述】:

简单的 OData 查询很简单,如果所有内容在编译时都是已知的。我已经学会了如何在运行时构建表达式以进行过滤,但我还没有完全弄清楚如何在运行时构建 OrderBy 表达式?

查询模型示例(动态过滤器表达式):

var empls = await client.For<MyModel>("MyTable")
                    .Top(request.PageSize)
                    .Skip((request.Page - 1) * request.PageSize)
                    .Filter(filter)
                    .FindEntriesAsync();

如果我在编译时知道需要什么顺序,我可以添加一个 .OrderBy() 子句。但是由于用户在运行时决定排序,所以我需要构建一个排序表达式。

为了动态构建上面传递的过滤器,我使用了 ODataExpression 对象。我正在寻找传递给 order 子句的等效功能(如果存在的话?)。

【问题讨论】:

  • 嗯,你是什么意思? Odata 用于动态过滤,因此它在运行时运行。您应该使用 Odata 元数据来构建查询。
  • 我将举例说明。我有一个 Kendo 网格用来查询数据的 MVC 控制器方法。如果我确信只有合理数量的记录返回到网格,我可以将它们全部返回并让网格在客户端管理过滤和排序。但是,如果我实现服务器端分页,这意味着服务器端代码需要根据网格为过滤器和排序传递的内容来管理过滤和排序(以响应网格上的用户操作)。
  • 以同样的方式对待他们。 1. 为这些端点设置足够高的页面大小,以便它们在一个页面中全部返回。 2. OData 具有内置的分页和过滤功能,例如 Products?$top=10&amp;$skip=20 3. 您可以将 ODataQuery 应用于现有的 IQueryable,例如让您的控制器接收 ODataQueryOptions&lt;Product&gt; options,然后您可以调用 options.ApplyTo(_products.AsQueryable())
  • 重点是处理未知数量的记录,数千甚至数百万。我不一定能一次加载所有记录。用户决定页面大小。分页不是问题。 OrderBy 是目前唯一需要解决的问题。
  • 你对什么感到困惑? OData 提供允许您从客户端构建过滤器的元数据。您正在手动尝试在 api 中应用过滤器。可能是因为默认实现有其局限性。所以将你的默认查询传递给 QueryOptions 并使用 apply 来处理过滤和排序。

标签: odata


【解决方案1】:

无需在单个语句中编写和执行 OData 请求。简单 OData API 旨在让您有选择地构建查询以随时实现您的业务逻辑。

需要知道升序降序之间的选择,以及要排序的列(或多个列)的名称,这些避风港的详细信息'没有在原始帖子中提供,所以在这里我假设sortColumn 是一个定义用户选择的列的字符串,sortDescending 是一个标志,指示排序方向是否为升序 em> (false) 或降序 (True) 顺序。

var query = client.For<MyModel>("MyTable")
                  .Top(request.PageSize)
                  .Skip((request.Page - 1) * request.PageSize)
                  .Filter(filter);
if (sortDescending)
    query = query.OrderByDescending(sortColumn);
else
    query = query.OrderBy(sortColumn);

var empls = await query.FindEntriesAsync(); 

还有其他技术可用于实现类似的结果,但它们的适用性在很大程度上取决于您存储要排序的列的方式、是否允许多列排序以及是否允许多列中的不同方向排序。

【讨论】:

  • 实际上可以有多个排序列。当我编写 OP 时,我还不明白您可以多次调用 Filter 和 OrderBy(绝对没有我在网上看到的示例或在我们的代码中这样做)。当然,多次调用 Filter 的行为类似于 AND 操作。我将进行测试,但此时我假设第二次调用 OrderBy 与在 SQL 查询中的子句之间添加逗号具有相同的效果。
  • @jrichview 实际上添加多个对 Order By 的调用将具有反转 SQL 中子句的相同效果,因此请注意调用它们的顺序,否则您应该使用 .ThenBy() 或者您可以使用OrderBy(string[] columns) 的数组重载来指定具有预期优先级的所有列。
  • ...和/或 ThenByDescending()。实际上,在我们的情况下,唯一会出现多个是当不按人的姓/名排序时,他们的名字将自动添加为辅助排序。很常见的情况,真的。
  • 虽然我似乎能够将字符串字段名称传递给 OrderBy() 子句,但如果我尝试将其传递给 ThenBy() 子句,它会将其标记为错误,因为 ThenBy()没有接受字符串的重载。显然你必须构建一个表达式对象。
【解决方案2】:

我注意到 Fluent 客户端界面的另一个 OrderBy() 重载:

OrderBy(IEnumerable<KeyValuePair<string, bool>> columns);

如果您需要动态多级排序,您可以创建一个 List> 并使用 KeyValuePair 对象填充它,其中字符串是字段规范,bool 为 false 表示 ASCENDING并且适用于 DESCENDING 排序。

请确保您的字符串使用正斜杠“/”作为字段路径分隔符而不是句点。

排序层次结构将按照您将 KeyValuePairs 添加到列表中的顺序。所以如果你想排序:

  1. Person.LastName ASC
  2. Person.FirstName ASC
  3. Person.EmployerName DESC

您只需按上述顺序将对象添加到列表中,就像您期望为布尔值传递 false、false、true 一样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-19
    相关资源
    最近更新 更多