我正在使用simple.odata.client v4来访问我的odata rest api。数据模型非常复杂。我遇到的问题是,我只想获取相关实体满足涉及可为空的日期时间偏移量(OnHandLastUpdate)的属性的条件的实体。实际上在 api 方面,它是一个可为空的日期时间,但我认为 odata v4 会自动转换它。我尝试运行的代码是:
var items =
oDataClient.For<ClientProductSku>()
.Filter(x => x.ClientId == clientId && x.Product.SupplierProductSkuClient
.All(y => y.SupplierProductSku.SupplierProductSkuOnHand
.Any(z => z.OnHandLastUpdated.HasValue && z.OnHandLastUpdated.Value > DateTimeOffset.Now.AddMinutes(-5))))
.Expand(UpdateSkuOnhandExpandTables)
.FindEntriesAsync(annotations)
.Result;
我得到的错误如下:
"error":{
"code":"","message":"The query specified in the URI is not valid. Can only bind segments that are Navigation, Structural, Complex, or Collections. We found a segment 'OnHandLastUpdated' that isn't any of those. Please revise the query.","innererror":{
"message":"Can only bind segments that are Navigation, Structural, Complex, or Collections. We found a segment 'OnHandLastUpdated' that isn't any of those. Please revise the query.","type":"Microsoft.OData.Core.ODataException","stacktrace":" at Microsoft.OData.Core.UriParser.Parsers.InnerPathTokenBinder.BindInnerPathSegment(InnerPathToken segmentToken)rn at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.BindInnerPathSegment(InnerPathToken token)rn at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.Bind(QueryToken token)rn at Microsoft.OData.Core.UriParser.Parsers.EndPathBinder.DetermineParentNode(EndPathToken segmentToken)rn at Microsoft.OData.Core.UriParser.Parsers.EndPathBinder.BindEndPath(EndPathToken endPathToken)rn at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.BindEndPath(EndPathToken endPathToken)rn at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.Bind(QueryToken token)rn at Microsoft.OData.Core.UriParser.Parsers.BinaryOperatorBinder.GetOperandFromToken(BinaryOperatorKind operatorKind, QueryToken queryToken)rn at Microsoft.OData.Core.UriParser.Parsers.BinaryOperatorBinder.BindBinaryOperator(BinaryOperatorToken binaryOperatorToken)rn at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.BindBinaryOperator(BinaryOperatorToken binaryOperatorToken)rn at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.Bind(QueryToken token)rn at Microsoft.OData.Core.UriParser.Parsers.LambdaBinder.BindExpressionToken(QueryToken queryToken)rn at Microsoft.OData.Core.UriParser.Parsers.LambdaBinder.BindLambdaToken(LambdaToken lambdaToken, BindingState state)rn at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.BindAnyAll(LambdaToken lambdaToken)rn at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.Bind(QueryToken token)rn at Microsoft.OData.Core.UriParser.Parsers.LambdaBinder.BindExpressionToken(QueryToken queryToken)rn at Microsoft.OData.Core.UriParser.Parsers.LambdaBinder.BindLambdaToken(LambdaToken lambdaToken, BindingState state)rn at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.BindAnyAll(LambdaToken lambdaToken)rn at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.Bind(QueryToken token)rn at Microsoft.OData.Core.UriParser.Parsers.BinaryOperatorBinder.GetOperandFromToken(BinaryOperatorKind operatorKind, QueryToken queryToken)rn at Microsoft.OData.Core.UriParser.Parsers.BinaryOperatorBinder.BindBinaryOperator(BinaryOperatorToken binaryOperatorToken)rn at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.BindBinaryOperator(BinaryOperatorToken binaryOperatorToken)rn at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.Bind(QueryToken token)rn at Microsoft.OData.Core.UriParser.Parsers.FilterBinder.BindFilter(QueryToken filter)rn at Microsoft.OData.Core.UriParser.ODataQueryOptionParser.ParseFilterImplementation(String filter, ODataUriParserConfiguration configuration, IEdmType elementType, IEdmNavigationSource navigationSource)rn at Microsoft.OData.Core.UriParser.ODataQueryOptionParser.ParseFilter()rn at System.Web.OData.Query.FilterQueryOption.get_FilterClause()rn at System.Web.OData.Query.Validators.FilterQueryValidator.Validate(FilterQueryOption filterQueryOption, ODataValidationSettings settings)rn at System.Web.OData.Query.FilterQueryOption.Validate(ODataValidationSettings validationSettings)rn at System.Web.OData.Query.Validators.ODataQueryValidator.Validate(ODataQueryOptions options, ODataValidationSettings validationSettings)rn at System.Web.OData.Query.ODataQueryOptions.Validate(ODataValidationSettings validationSettings)rn at System.Web.OData.EnableQueryAttribute.ValidateQuery(HttpRequestMessage request, ODataQueryOptions queryOptions)rn at System.Web.OData.EnableQueryAttribute.ExecuteQuery(Object response, HttpRequestMessage request, HttpActionDescriptor actionDescriptor)rn at System.Web.OData.EnableQueryAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)"
}
我在某处读到,odata v4 中尚未完全支持可为空的日期时间和日期时间偏移量,这可能会导致此问题。无论如何,是否有解决方法来实现上述查询?
我相信这是Simple.OData.Client的当前限制。它具有一个内置的表达式分析器,其工作方式与其他 LINQ 提供程序类似。它将 C# 表达式转换为 OData URI。发生的情况是,它将 HasValue 视为 OnHandLastUpdated 的属性,即 OnHandLastUpdated 被解释为 ComplexType,因此您会收到此错误。
我将在Simple.OData.Client GitHub上注册一个问题,看看这是否可以轻松解决。
我检查了库,看起来您可以像这样重写查询:
var items =
oDataClient.For<ClientProductSku>()
.Filter(x => x.ClientId == clientId && x.Product.SupplierProductSkuClient
.All(y => y.SupplierProductSku.SupplierProductSkuOnHand
.Any(z => z.OnHandLastUpdated.Value > DateTimeOffset.Now.AddMinutes(-5))))
.Expand(UpdateSkuOnhandExpandTables)
.FindEntriesAsync(annotations)
.Result;
你能试试吗?我相信它应该有效。
FWIW,我正在手动创建表达式树并遇到了同样的问题。我决定四处闲逛并尝试一些东西,并利用@Vagif Abilov的回答将问题缩小到明确使用HasValue
属性。
如果您与null
进行比较而不是Nullable<DateTimeOffset>.HasValue
它有效,并且您不必捏造任何依赖于可为空测试的测试或为 OData 框架提供特殊情况。
因此,按照上面的示例,您应该能够执行以下操作:
var items = oDataClient.For<ClientProductSku>()
.Filter(x => x.ClientId == clientId && x.Product.SupplierProductSkuClient
.All(y => y.SupplierProductSku.SupplierProductSkuOnHand
.Any(z => z.OnHandLastUpdated != null &&
z.OnHandLastUpdated.Value > DateTimeOffset.Now.AddMinutes(-5))))
.Expand(UpdateSkuOnhandExpandTables)
.FindEntriesAsync(annotations)
.Result;