3

Update

vote here on User Voice to get the ambiguity addressed.


I've written a OData WebAPI controller inherting from ODataController.

public class ManyColumnsController : ODataController
{
    [Queryable(
        AllowedOrderByProperties = "Aa,Bb,Cc,Dd",
        EnsureStableOrdering = false,
        MaxOrderByNodeCount = 2)]
    public IQueryable<ManyColumn> GetManyColumns(
            ODataQueryOptions<ManyColumn> options)
    {
        // Because I've disabled EnsureStableOrdering,
        // I need to check column "Dd" is always included
        // in the OrderBy option. This will ensure stable ordering.
        if (!options.OrderBy.RawValue.Contains("Dd")
        {
             var entityType = options.Context.ElementType as IEdmEntityType;
             var ddProperty = entityType.DeclaredStructuralProperties()
                 .Single(p => p.Name == "Dd");
             options.OrderBy.OrderByNodes.Add(new OrderByPropertyNode(
                 ddProperty,
                 OrderByDirection.Descending));
        }

        return this.context.ManyColumns;
    }
}

This code runs and an extra OrderByNode is added to the OrderBy property of the ODataQueryOptions passed into the method.

The Problem

This alteration has no effect on the statement that is generated by the contoller. Processing continues as if I had changed nothing and any OrderBy applied to the ManyColumns entity is replaced with the orignal OrderBy specified in the $orderby parameter of the original request.

On further examination it seems that ODataQueryOptions is probably intended to be immutable. Most of its properties have only get accessors.

The Question

Have I just misused a failing in the implementation of OrderByQueryOption?

Is there a way to amend the ODataQueryOptions that will be applied to the request, later in the pipeline?

Jodrell
  • 34,946
  • 5
  • 87
  • 124

3 Answers3

4

You should remove the [Queryable] attribute.

According to http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options#ODataQueryOptions, you should use either Queryable or manually manipulate the ODataQueryOptions. The web API populates the ODataQueryOptions from the URI query string, after which you could (presumably) alter those options.

Further down the page, they implement something that looks really close to a solution for your problem. They implement a custom MyQueryable attribute which enforces a custom order-by validator. You may not be able to alter the query during validation, but you may be able to override the attribute's implementation of ApplyQuery to inject your required order-by clause.

Colby Cavin
  • 492
  • 2
  • 6
  • This is in-fact what I ended up doing. It took a lot of extra work but I had to combine Full-Text Searching with server side paging so had to "hand roll" the SQL anyway. – Jodrell May 19 '14 at 08:45
2

If you have ODataQueryOptions as the method parameter, it means that you want to handle the options yourself. So try this:

return options.ApplyTo(this.context.ManyColumns.AsQueryable());
Tan Jinfu
  • 3,327
  • 1
  • 19
  • 20
  • but, does this stop the options being reapplied later in the pipeline, after returning? Not in my testing. – Jodrell May 07 '14 at 10:29
  • Maybe if I dropped the `Queryable` arttribute but then I'd have to perform the validation too. – Jodrell May 07 '14 at 10:36
1

By default all the querys are orderer by the table's PrimaryKey if no $orderby is specified

This code dont work, allways order by the primary key

[Queryable]
public IQueryable<Coches> GetCoches()
{
return db.Coches.OrderByDescending(c => c.Marca);
}

For override that behavior use this parameter in the Queyable attribute

[Queryable(EnsureStableOrdering=false)]
public IQueryable<Coches> GetCoches()
{
return db.Coches.OrderByDescending(c=>c.Marca);
}

The previous code work fine, the return values are orderer by Marca, or by the value in the $orderby parameter if specified

FRL
  • 748
  • 7
  • 9
  • so, I'd like to add clauses to the end of the specified `$orderby` or set a default if no `$orderby` is specified. – Jodrell Jun 02 '14 at 07:49