Filter 如何修改OData查询以添加访问筛选器?

Filter 如何修改OData查询以添加访问筛选器?,filter,nested,odata,Filter,Nested,Odata,我有一个C OData端点,在这里我需要评估随OData查询提交的过滤器,以确定是否需要添加额外的过滤器来限制返回给用户的结果 我的示例模型很简单: 学生->图书目录->图书 所有实体都有分配给它们的CampusId属性 当用户属于校园5时,执行以下查询: 学生$select=Id、姓名、CampusId 应将其转变为: 学生$select=Id、姓名、CampusId和$filter=CampusId eq 5 我可以通过简单的查询来实现这一点,只需添加一个过滤器作为字符串 我真正想做的是:

我有一个C OData端点,在这里我需要评估随OData查询提交的过滤器,以确定是否需要添加额外的过滤器来限制返回给用户的结果

我的示例模型很简单:

学生->图书目录->图书 所有实体都有分配给它们的CampusId属性

当用户属于校园5时,执行以下查询: 学生$select=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查询Uri中的当前过滤器值

有人知道如何编辑FilterClause中的值,以便能够向Uri添加新的筛选器值吗


关于如何编辑FilterClause以生成具有新筛选器值的更新Uri,我没有找到太多的示例。

我通过编写一个算法来找到isse的解决方案,该算法根据模型的属性向请求添加额外的筛选。它检查根级别实体的任何属性以及任何扩展实体的属性,以确定要添加到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)
我用于完成此任务的步骤:

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

var parser = new ODataUriParser(model, new Uri(serviceRootPath), requestUri);   
var odataUri = parser.ParseUri();
var updatedODataUri = new Microsoft.OData.Core.UriBuilder.ODataUriBuilder(ODataUrlConventions.Default, odataUri).BuildUri();
创建一个方法,该方法将从根向下遍历到所有展开的实体,并通过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.创建了一个新的filter子句,因此任何附加的filter表达式都只需附加到ODataUri中已有的任何现有filter表达式中

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

var parser = new ODataUriParser(model, new Uri(serviceRootPath), requestUri);   
var odataUri = parser.ParseUri();
var updatedODataUri = new Microsoft.OData.Core.UriBuilder.ODataUriBuilder(ODataUrlConventions.Default, odataUri).BuildUri();
用更新的Uri替换请求Uri。 这允许OData控制器使用更新的OData Url完成对请求的处理,该Url包括您刚刚添加到根级文件管理器的附加筛选选项

ActionContext.Request.RequestUri = updatedODataUri;
这使我能够添加所需的任何过滤选项,并100%确保我没有错误地更改ODataURL结构


我希望这能帮助其他人解决同样的问题。

我在这里有一个答案,可以更改控制器中的过滤器值:谢谢,但这没有帮助。事实上,您提到的响应中的答案只有在您已经知道ODataURI字符串的结构时才起作用。实际上,筛选器值可以包括各种其他设置startsWith、Contains等,因此简单的字符串替换无法可靠地工作。正确的解决方案应该允许我们检查现有的筛选器表达式树,并在必要时附加到它,而不会干扰它已经包含的任何现有筛选器值。对于它的价值,我想我在这里问了一个几乎相同的问题:还没有得到很好的答案,但它可能会为您提供一些更好的问题背景 添加的额外筛选条件不会添加父实体:我创建了一个问题。您现在正在运行AspNetCore吗?