我通过编写一个算法,在我的模型属性基础上为请求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)
我用以下步骤完成了这个任务:
- 使用ODataUriParser将传入的Url解析为Uri对象
具体请参见下文:
var parser = new ODataUriParser(model, new Uri(serviceRootPath), requestUri)
var odataUri = parser.ParseUri()
- 创建一个方法,从根节点下降到所有展开的实体,并通过引用传递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 控制器使用包含您刚刚添加到根级筛选器的其他筛选选项的更新后的 OData Url 完成处理请求。
ActionContext.Request.RequestUri = updatedODataUri
这使我能够添加任何所需的筛选选项,并确信我没有错误地更改了OData Url结构。希望这篇文章能帮助其他遇到同样问题的人。