entity-framework - OData v4 结果后处理(适用于 v3,不适用于 v4)
问题描述
我有一个 Web API 服务器(使用 EF 6.x),我需要对控制器中 OData 查询的结果集进行一些后处理。在客户端,我使用 DevEx 网格和他们的 ODataInstantFeedbackSource。
没有后处理,一切正常,例如:
http://somesite.us/odata/Items/ $count
[EnableQuery]
public IHttpActionResult GetItems(ODataQueryOptions<Item> queryOptions)
{
return Ok(Context.Items);
}
它不适用于后处理(相同的简单 $count 查询,但没有 EnableQuery,因为我手动应用查询选项):
获取http://somesite.us/odata/Items/ $count
//[EnableQuery]
public IHttpActionResult GetItems(ODataQueryOptions<Item> queryOptions)
{
queryOptions.Validate(_validationSettings);
var query = queryOptions.ApplyTo(Context.Items, new ODataQuerySettings()) as IQueryable<Item>;
var resultList = new List<Item>();
foreach (var item in query)
{
item.OrdStat = "asf"; // Some post-processing
resultList.Add(item);
}
return Ok(resultList.AsQueryable());
}
这会引发异常:
Microsoft.OData.ODataException
HResult=0x80131509
Message=The value of type 'System.Linq.EnumerableQuery`1[[SomeService.Model.Item, SomeService.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' could not be converted to a raw string.
Source=Microsoft.OData.Core
StackTrace:
at Microsoft.OData.RawValueWriter.WriteRawValue(Object value)
注意:使用 ODATA v3,上述工作正常。只有在 v4 中,不使用 [EnableQuery] 时才会出现异常。
如果我添加回 [EnableQuery] 属性,这个简单的 $count 查询适用于 ODATA v4,但对于更复杂的查询,返回给客户端的数据会变得混乱(可能是由于 $skip 等被我和通过 EnableQuery 属性)。
例如,向下滚动时 DevEx 网格生成的这个查询: http://somesite.us/odata/Items ?$orderby=ItemNo&$skip=300&$top=201
结果(客户端):意外的返回键数:0。预期:201
我假设我需要删除 EnableQuery 属性,因为我正在手动应用查询选项,但是为什么在执行此操作时会出现“无法转换为原始字符串”异常?
在这种情况下如何正确实施后处理?
解决方案
我就此向 Microsoft 提出了支持请求,他们最终确定这是 ODATA v4 中的一个错误,他们创建了这个错误报告: https ://github.com/OData/WebApi/issues/1586
解决方法是检查查询是否为计数查询,如果是,则返回 Ok(query.Count());
if (queryOptions.Context.Path?.Segments.LastOrDefault() is CountSegment)
return Ok(query?.Count());
这是一个更完整的示例片段/POC,它适用于 ODATA v4:
private static ODataValidationSettings _validationSettings = new ODataValidationSettings();
[ODataRoute("Customers")]
public IHttpActionResult Get(ODataQueryOptions<CustomerLookup> queryOptions)
{
queryOptions.Validate(_validationSettings);
var query = queryOptions.ApplyTo(Context.CustomerLookup) as IQueryable<CustomerLookup>;
if (queryOptions.Context.Path?.Segments.LastOrDefault() is CountSegment)
return Ok(query?.Count());
var resultList = new List<CustomerLookup>();
foreach (var customer in query)
{
customer.Address = "1234_" + customer.Address;
resultList.Add(customer);
}
return Ok(resultList.AsQueryable());
}
推荐阅读
- oracle - oracle中有“立即执行”时如何实现refcursor?
- reactjs - 如何访问数组对象中的元素 [API]
- reactjs - 当InfiniteScroll在reactjs中向下滚动时如何保持其他组件保持在顶部位置
- python - 我如何处理基本矩阵?
- java - 如何使用 valueOf 将字符串数组转换为 int 数组?
- azure-devops - 如何从 Azure 数据工厂 v2 中的 Azure DevOps Git 存储库内容读取代码
- node.js - 如何从 cloudinary 访问上传功能之外的变量
- pyspark - PySpark 中的数据框求和
- reactjs - 打字稿“编译失败”错误作为警告
- google-apps-script - 清除删除行的内容