OData / WebApi

OData Web API: A server library built upon ODataLib and WebApi
https://docs.microsoft.com/odata
Other
855 stars 473 forks source link

Wrong Binding $it range variable #2600

Open xuzhg opened 3 years ago

xuzhg commented 3 years ago

Short summary (3-5 sentences) describing the issue.

Example 106: customers along with their orders that shipped to the same city as the customer's address. The nested filter expression is evaluated in the context of Orders; $it allows referring to values in the outer context of Customers.

http://host/service/Customers?$expand=Orders($filter=$it/Address/City eq ShipTo/City)

ODL query option parser the nested $filter as:


FilterClause: RangeVariable (name: "$it", type: "Order")

  --- Expression: BinaryOperatorNode
                   --- Left:   SinglePropertyAccessNode
                                                 --- Source: (RangeVariableReferenceNode) (name: "$it", type: "Customer")

                   --- Right:   SinglePropertyAccessNode
                                                 --- Source: (RangeVariableReferenceNode) (name: "$it", type: "Order")

You can see the nested $filter has three range variables related, all named "$it".

When we do the bind, it tries to get the "$it" parameter when do the left, as the following debug:

image

Then, here's the example:

System.ArgumentException: Instance property 'xxxx' is not defined for type 'AspNetCore3xEndpointSample.Web.Models.Order' (Parameter 'propertyName')
 at System.Linq.Expressions.Expression.Property(Expression expression, String propertyName)
   at Microsoft.AspNet.OData.Query.Expressions.ExpressionBinderBase.GetPropertyExpression(Expression source, String propertyPath) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\ExpressionBinderBase.cs:line 1189
   at Microsoft.AspNet.OData.Query.Expressions.ExpressionBinderBase.CreatePropertyAccessExpression(Expression source, IEdmProperty property, String propertyPath) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\ExpressionBinderBase.cs:line 1178
   at Microsoft.AspNet.OData.Query.Expressions.FilterBinder.BindPropertyAccessQueryNode(SingleValuePropertyAccessNode propertyAccessNode) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\FilterBinder.cs:line 681
   at Microsoft.AspNet.OData.Query.Expressions.FilterBinder.BindSingleValueNode(SingleValueNode node) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\FilterBinder.cs:line 856
   at Microsoft.AspNet.OData.Query.Expressions.FilterBinder.Bind(QueryNode node) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\FilterBinder.cs:line 203
   at Microsoft.AspNet.OData.Query.Expressions.FilterBinder.BindBinaryOperatorNode(BinaryOperatorNode binaryOperatorNode) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\FilterBinder.cs:line 502
   at Microsoft.AspNet.OData.Query.Expressions.FilterBinder.BindSingleValueNode(SingleValueNode node) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\FilterBinder.cs:line 841
   at Microsoft.AspNet.OData.Query.Expressions.FilterBinder.Bind(QueryNode node) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\FilterBinder.cs:line 203
   at Microsoft.AspNet.OData.Query.Expressions.FilterBinder.BindExpression(SingleValueNode expression, RangeVariable rangeVariable, Type elementType) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\FilterBinder.cs:line 602
   at Microsoft.AspNet.OData.Query.Expressions.FilterBinder.BindFilterClause(FilterBinder binder, FilterClause filterClause, Type filterType) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\FilterBinder.cs:line 165
   at Microsoft.AspNet.OData.Query.Expressions.FilterBinder.Bind(IQueryable baseQuery, FilterClause filterClause, Type filterType, ODataQueryContext context, ODataQuerySettings querySettings) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\FilterBinder.cs:line 81
   at Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder.CreatePropertyValueExpression(IEdmStructuredType elementType, IEdmProperty property, Expression source, FilterClause filterClause) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\SelectExpandBinder.cs:line 210
   at Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder.BuildExpandedProperty(Expression source, IEdmStructuredType structuredType, IEdmNavigationProperty navigationProperty, ExpandedReferenceSelectItem expandedItem, IList`1 includedProperties) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\SelectExpandBinder.cs:line 711
   at Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder.BuildPropertyContainer(Expression source, IEdmStructuredType structuredType, IDictionary`2 propertiesToExpand, IDictionary`2 propertiesToInclude, ISet`1 autoSelectedProperties, Boolean isSelectingOpenTypeSegments) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\SelectExpandBinder.cs:line 643
   at Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder.ProjectElement(Expression source, SelectExpandClause selectExpandClause, IEdmStructuredType structuredType, IEdmNavigationSource navigationSource) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\SelectExpandBinder.cs:line 336
   at Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder.GetProjectionLambda(SelectExpandQueryOption selectExpandQuery) in D:\github\odata\WebApi\src\Microsoft.AspNet.OData.Shared\Query\Expressions\SelectExpandBinder.cs:line 98
xuzhg commented 3 years ago

The potential fix at ODL: 1) make the "source" == null if there's no "$it". For example the "Right" at the above. Then, at Web API, if the source == null, we use the "current" parameter.

2) create "source" if there's a "$it" or "$this", For example the "above" at the above.