OData / AspNetCoreOData

ASP.NET Core OData: A server library built upon ODataLib and ASP.NET Core
Other
457 stars 158 forks source link

Wrong Binding $it range variable #375

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
wbuck commented 1 year ago

This issue sounds some what related to something I'm seeing (which may be the correct behavior but I'm unsure).

Given the following:

class Entity
{
    public Guid Id { get; set; }
    public ICollection<int> Values { get; set; } = new List<int>();
}

And using the following query:

`?$select=Values($filter=$this gt 1000)`

I notice that the FilterClause.RangeVariable.Name is equal to $it, which isn't what I expected. My expectation was for FilterClause.RangeVariable.Name to be equal to the literal $this and not $it.

Is the behavior above correct? Should FilterClause.RangeVariable.Name be equal to $it for the above query?

Library version: 8.0.6