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

标签 filter nested odata

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

我的示例模型很简单:

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

当属于 Campus #5 的用户执行以下查询时: "学生$select=身份证号,姓名,校园号" 它应该转换为: “Students$select=Id,姓名,CampusId&$filter=CampusId eq 5”

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

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

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

例如:

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

使用上面的代码片段,您可以获取“filter”变量来提供 Microsoft.OData.Core.UriParser.Semantic.FilterClause 类型,该类型可用于检查OData 查询 Uri。

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

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

最佳答案

我通过编写一种算法找到了解决问题的方法,该算法根据模型的属性向请求 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对象

见下文:

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

    AddCustomFilters(ref ODataUri odataUri);
    

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

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

    方法 AddCustomFiltersToExpandedEntity 应在循环遍历每个级别的扩展实体时调用自身。

  • 在检查每个实体时更新根过滤器
  • 根据您的附加过滤器要求创建新的过滤器子句,并覆盖根级别的现有过滤器子句。 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);
    
  • 使用 ODataUriBuilder 根据更新的 Uri 创建新的 Url
  • 见下文:

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

    ActionContext.Request.RequestUri = updatedODataUri;
    

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

    我希望这可以帮助其他人在面临同样的问题时。

    关于filter - 如何修改 OData 查询以添加访问过滤器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37424356/

    相关文章:

    c# - 从 C# 中的列表中完全删除所有至少有一个重复项的元素

    Django 自递归 ManyToManyField 过滤查询

    eclipse - Eclipse 中的嵌套项目和项目文件夹

    odata - 表动态加载 SAPUI5/UI5

    java - 尝试连接到数据市场返回异常

    java - 在Java8中使用过滤器和映射提取数据库列数据

    Magento 子类别分层导航未显示

    if-statement - GW-BASIC 中的嵌套 IF...THEN...ELSE

    Python:如何创建嵌套容器的散列

    c# - OData 和 WCF : Unable to perform POST, 放置和删除