raf
raf

Reputation: 31

ASP.NET OData - $orderby fails on a derived type property

$orderby fails on a derived type property

Assemblies affected

System.Web.OData 5.9.1.0 Microsoft.OData.Core 6.15.0.0

Reproduce steps

*Model:

    public abstract class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    public class Manager : Person
    {
        public string ManagerProperty { get; set; }
    }
    public class Supervisor : Person
    {
        public string SupervisorProperty { get; set; }
    }

If I query now to order on a derived Members property I get an error

Query:

http://someserver/odata/persons?$isof=('Namespace.Manager')&$orderby=Namespace.Manager/ManagerProperty

Error Details:

"message":"The method or operation is not implemented.","type":"System.NotImplementedException","stacktrace":" at Microsoft.OData.Core.UriParser.Visitors.QueryNodeVisitor`1.Visit(SingleEntityCastNode nodeIn)\r\n at System.Web.OData.Query.Validators.OrderByQueryValidator.OrderByModelLimitationsValidator.TryValidate(OrderByClause orderByClause, Boolean explicitPropertiesDefined)\r\n at System.Web.OData.Query.Validators.OrderByQueryValidator.Validate(OrderByQueryOption orderByOption, ODataValidationSettings validationSettings)\r\n at System.Web.OData.Query.OrderByQueryOption.Validate(ODataValidationSettings validationSettings)\r\n at System.Web.OData.Query.Validators.ODataQueryValidator.Validate(ODataQueryOptions options, ODataValidationSettings validationSettings)\r\n at System.Web.OData.Query.ODataQueryOptions.Validate(ODataValidationSettings validationSettings)\r\n at System.Web.OData.EnableQueryAttribute.ValidateQuery(HttpRequestMessage request, ODataQueryOptions queryOptions)\r\n at System.Web.OData.EnableQueryAttribute.ExecuteQuery(Object response, HttpRequestMessage request, HttpActionDescriptor actionDescriptor)\r\n at System.Web.OData.EnableQueryAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)"
•

Expected result

It should order the results by specified property

Actual result

*"message":"The method or operation is not implemented.","type":"System.NotImplementedException","stacktrace":" at Microsoft.OData.Core.UriParser.Visitors.QueryNodeVisitor`1.Visit(SingleEntityCastNode nodeIn)\r\n at System.Web.OData.Query.Validators.OrderByQueryValidator.OrderByModelLimitationsValidator.TryValidate(OrderByClause orderByClause, Boolean explicitPropertiesDefined)\r\n at System.Web.OData.Query.Validators.OrderByQueryValidator.Validate(OrderByQueryOption orderByOption, ODataValidationSettings validationSettings)\r\n at System.Web.OData.Query.OrderByQueryOption.Validate(ODataValidationSettings validationSettings)\r\n at System.Web.OData.Query.Validators.ODataQueryValidator.Validate(ODataQueryOptions options, ODataValidationSettings validationSettings)\r\n at System.Web.OData.Query.ODataQueryOptions.Validate(ODataValidationSettings validationSettings)\r\n at System.Web.OData.EnableQueryAttribute.ValidateQuery(HttpRequestMessage request, ODataQueryOptions queryOptions)\r\n at System.Web.OData.EnableQueryAttribute.ExecuteQuery(Object response, HttpRequestMessage request, HttpActionDescriptor actionDescriptor)\r\n at System.Web.OData.EnableQueryAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)"
 *

Breaks in following method in OrderByQueryValidator

public override SingleValueNode Visit(SingleValuePropertyAccessNode nodeIn)
            {
                if (EdmLibHelpers.IsNotSortable(nodeIn.Property, _model))
                {
                    return nodeIn;
                }
                if (nodeIn.Source != null)
                {
                    return nodeIn.Source.Accept(this);
                }
                return null;
            }

I then added following condition which fixed the issue but I am sure if that's the correct solution hence, can someone please advise

public override SingleValueNode Visit(SingleValuePropertyAccessNode nodeIn)
            {
                if (EdmLibHelpers.IsNotSortable(nodeIn.Property, _model))
                {
                    return nodeIn;
                }
                if (nodeIn.Source != null)
                {
                    if(((SingleEntityCastNode)nodeIn.Source).EntityTypeReference != ((SingleEntityCastNode)nodeIn.Source).Source.EntityTypeReference)
                    {
                        return ((SingleEntityCastNode)nodeIn.Source).Source.Accept(this);
                    }
                    return nodeIn.Source.Accept(this);
                }
                return null;
            }

Upvotes: 2

Views: 526

Answers (1)

it's better to go directly to override Visit method of SingleEntityCastNode parameter, with this you avoid errors of other node types:

        public override SingleValueNode Visit(SingleValuePropertyAccessNode nodeIn)
        {
            if (EdmLibHelpers_IsNotSortable(nodeIn.Property, _model))
            {
                return nodeIn;
            }
            if (nodeIn.Source != null)
            {               
                return nodeIn.Source.Accept(this);
            }
            return null;
        }

        public override SingleValueNode Visit(SingleEntityCastNode nodeIn)
        {
            if (nodeIn.EntityTypeReference != nodeIn.Source.EntityTypeReference)
            {
                return nodeIn.Source.Accept(this);
            }
            return base.Visit(nodeIn);
        }

Also see https://github.com/OData/WebApi/issues/861

Upvotes: 1

Related Questions