如何修改OData查询以添加访问过滤器?

时间:2016-05-24 21:38:16

标签: filter nested odata

我有一个C#OData端点,我需要评估使用OData查询提交的过滤器,以确定是否需要添加其他过滤器来限制返回给用户的结果。

我的示例模型很简单:

学生 - >图书目录 - >图书 (所有实体都分配了CampusId属性。)

当属于Campus#5的用户执行以下查询时: “学生$选择= ID,名字,CampusId” 它应该转变为: “学生$ select = Id,姓名,CampusId& $ filter = CampusId eq 5”

我只需将过滤器添加为字符串即可通过简单查询完成此操作。

我真正想做的是: 1)确定正在选择和扩展的实体 2)确定这些实体是否具有CampusId属性 3)将必要的过滤器值添加到Uri中,以便将每个选定和/或扩展实体的查询过滤到该校园

我正在尝试使用Microsoft.OData.Core.UriParser.ODataUriParser来解析过滤器值,然后创建一个新的Uri。

例如:

var parser = new Microsoft.OData.Core.UriParser.ODataUriParser(edmModel, new Uri(serviceRootPath), originalUri);
var filter = parser.ParseFilter();

使用上面的代码片段,您可以获得“过滤器”变量,以提供一种 Microsoft.OData.Core.UriParser.Semantic.FilterClause ,可用于检查当前过滤器值OData Query Uri。

是否有人知道如何编辑 FilterClause 中的值以便能够向Uri添加新的过滤器值?

我没有找到很多关于如何编辑FilterClause的示例,以便使用新的过滤器值生成更新的Uri。

1 个答案:

答案 0 :(得分:2)

我通过编写一个算法来找到解决方案,该算法根据模型的属性为请求ODataUri添加额外的过滤。它检查根级实体的任何属性以及任何扩展实体的属性,以确定要添加到OData查询的其他过滤器表达式。

OData v4支持在$ expand子句中进行过滤,但扩展实体中的filterOption是只读的,因此您无法修改扩展实体的过滤器表达式。您只能检查扩展实体的filterOption内容。

我的解决方案是检查所有实体(根和扩展)的属性,然后在请求ODataUri的根过滤器中添加我需要的任何其他$ filter选项。

以下是OData请求Url的示例:

/RootEntity?$expand=OtherEntity($expand=SomeOtherEntity)

这是我更新后的OData请求Url:

/RootEntity?$filter=OtherEntity/SomeOtherEntity/Id eq 3&$expand=OtherEntity($expand=SomeOtherEntity)

我曾经做过的步骤:

  1. 使用ODataUriParser将传入的Url解析为Uri对象
  2. 见下文:

    var parser = new ODataUriParser(model, new Uri(serviceRootPath), requestUri);   
    var odataUri = parser.ParseUri();
    
    1. 创建一个方法,该方法将从根遍历到所有展开的实体,并通过ref传递ODataUri(以便在检查每个实体时根据需要更新它)
    2. 第一种方法将检查根实体,并根据根实体的属性添加任何其他过滤器。

      AddCustomFilters(ref ODataUri odataUri);
      

      AddCustomFilters 方法将遍历展开的实体并调用 AddCustomFiltersToExpandedEntity ,它将继续遍历所有展开的实体以添加任何必要的过滤器。

      foreach (var item in odatauri.SelectAndExpand.SelectedItems)
      {
          AddCustomFiltersToExpandedEntity(ref ODataUri odataUri, ExpandedNavigationSelectItem expandedNavigationSelectItem, string parentNavigationNameProperty)
      }
      

      方法 AddCustomFiltersToExpandedEntity 应调用自身,因为它会遍历每个级别的展开实体。

      1. 在检查每个实体时更新根过滤器
      2. 使用您的其他过滤器要求创建一个新的过滤器子句,并覆盖根级别的现有过滤器子句。 ODataUri根级别的$ filter有一个setter,因此可以覆盖它。

        odataUri.Filter = new FilterClause(newFilterExpression, newFilterRange);
        

        注意:我使用 BinaryOperatorKind.And 创建了一个新的过滤器子句,以便将任何其他过滤器表达式简单地附加到ODataUri中已有的任何现有过滤器表达式

        var combinedFilterExpression = new BinaryOperatorNode(BinaryOperatorKind.And, odataUri.Filter.Expression, newFilterExpression);
        odataUri.Filter = new FilterClause(combinedFilterExpression, newFilterRange);
        
        1. 使用ODataUriBuilder根据更新的Uri
        2. 创建新的Url

          见下文:

          var updatedODataUri = new Microsoft.OData.Core.UriBuilder.ODataUriBuilder(ODataUrlConventions.Default, odataUri).BuildUri();
          
          1. 将请求Uri替换为更新后的Uri。
          2. 这允许OData控制器使用更新的OData Url完成处理请求,其中包括您刚刚添加到根级别文件管理器的其他过滤器选项。

            ActionContext.Request.RequestUri = updatedODataUri;
            

            这使我能够添加我需要的任何过滤选项,并且100%确定我没有错误地更改OData Url结构。

            我希望在面对同样的问题时,这可以帮助别人。