OData 按 M-M 关系过滤

OData Filter by an M-M relationship

是否可以通过 M-M 关系中的链接实体过滤 odata,其中它必须包含所有第二个,但允许额外的?

假设我有: 学生 学生Class Class 我想找到所有学生,他们的入学人数包括 类 (101, 102, 103)

是的,OData v4 提供了 2 Lambda Operators 来计算集合上的布尔表达式。这些是 AnyAll,其中 Any return 如果 至少一个 子条目符合条件,则为记录,并且All 需要 所有 个子记录匹配。

在你的情况下,我们可以使用 Any:

5.1.1.10.1 any
The any operator applies a Boolean expression to each member of a collection and returns true if the expression is true for any member of the collection, otherwise it returns false. The any operator without an argument returns true if the collection is not empty.

Example 79: all Orders that have any Items with a Quantity greater than 100

http://host/service/Orders?$filter=Items/any(d:d/Quantity gt 100)

但是我们无法通过数组或值列表进行比较,因此我们必须将此查询分解为每个值的 Any 表达式并将它们 AND 在一起。
这听起来违反直觉,但下面的简单查询我们在 单个 Any 中使用 OR 会导致 Student 具有 一个或多个的匹配项class 中的 (101,102,103) 但不一定是 所有 个:

http://host/service/Students?$filter=Enrollments/Any(e:e/Class/Code eq '101' or e/Class/Code eq '102' or e/Class/Code eq '103')

如果他们必须参加 atleast all of 101,102,103 那么我们必须 AND 一个单独的 [=每个 classes 的 12=] 运算符,下面是每个 class 的 3 个单独查询和 AND 将它们放在一起的最终查询:

http://host/service/Students?$filter=Enrollments/Any(e:e/Class/Code eq '101')
http://host/service/Students?$filter=Enrollments/Any(e:e/Class/Code eq '102')
http://host/service/Students?$filter=Enrollments/Any(e:e/Class/Code eq '103')

http://host/service/Students?$filter=Enrollments/Any(e:e/Class/Code eq '101') AND Enrollments/Any(e:e/Class/Code eq '102') AND Enrollments/Any(e:e/Class/Code eq '103')

这些查询假定:
在名为 EnrollmentsStudent 记录上有一个导航 属性,它将 Student 链接到 StudentClass 的集合 记录,
StudentClass 有一个名为 'Class' 的导航 属性,将其链接到 单个 Class 记录,
class 代码 (101,102,103) 存储在 string 属性 在 Class 记录上调用 Code

NOTE: Different providers support these Lambda operators to different extents, you should check with your vendor/developer if you have have complex needs like support for nesting expressions with Any or All or if the simplest queries are not resolving as you expect.

这个查询没有特别要求 EnrollmentsClass 记录包含在结果中,它应该只是 return Students 的列表,除非有默认情况下,$expand 这些导航属性是服务器端配置或逻辑。


虽然 OP 不需要,但如果您正在扩展这些相同的对象图(您正在过滤),重要的是要指出在根 $filter 中使用 Any 运算符查询选项不会对展开的子集合应用过滤。如果您想要 return ONLY 与表达式匹配的子记录,您需要在 $expand 查询选项中实现 $filter 表达式,除了$filter查询选项中的Any运算符。

反之亦然,仅在 $expand 查询选项中使用 $filter 不会阻止顶级 Student 被 return 编辑,如果它们是只注册了其他 classes,它不会 return 任何 classes 因为它们不符合条件,但它仍然会 return Student记录。

因此,当使用 $filter 嵌套在 $expand 中时,很常见 包含 AnyAll 运算符在 $filter 查询选项中。