読者です 読者をやめる 読者になる 読者になる

かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

ASP.NET WebAPIのODataでクエリオプション取得する方法

とりあえず、個人的によく使うと思ったOrderByとTopとSkipだけ。

using Microsoft.Data.OData.Query;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http.OData;
using System.Web.Http.OData.Query;

namespace MvcApplication5.Controllers
{
    public class ProductsController : EntitySetController<Product, int>
    {
        private static readonly List<Product> Source = Enumerable
            .Range(1, 100)
            .Select(i => new Product { Id = i, Name = "Product" + i })
            .ToList();

        public override IQueryable<Product> Get()
        {
            var query = Source.AsQueryable();
            if (this.QueryOptions.OrderBy != null)
            {
                // ポイント。プロパティに対してorderbyしたときはOrderByPropertyNodeという型になる
                foreach (var node in this.QueryOptions.OrderBy.OrderByNodes.OfType<OrderByPropertyNode>())
                {
                    // とりあえずNameプロパティのみソートに応じる方向で
                    if (node.Property.Name == "Name")
                    {
                        query = 
                            node.Direction == OrderByDirection.Ascending ?
                                query.OrderBy(p => p.Name) :
                                query.OrderByDescending(p => p.Name);
                    }
                }
            }

            // Skip
            if (this.QueryOptions.Skip != null)
            {
                query = query.Skip(this.QueryOptions.Skip.Value);
            }

            // Top
            if (this.QueryOptions.Top != null)
            {
                query = query.Take(this.QueryOptions.Top.Value);
            }

            // 結果返す
            return query.ToArray().AsQueryable();
        }

        protected override Product GetEntityByKey(int key)
        {
            return Source.FirstOrDefault(p => p.Id == key);
        }
    }

    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

WebApiConfigには以下のようにODataサポートするようなルートを定義しておく。

var builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");
var model = builder.GetEdmModel();

config.Routes.MapODataRoute("OData", "odata", model);

ODataのクエリを受け取って、自分でパラメータを好きに解釈してやれるってのは、結構自由度高いんじゃないんだろうかと思う今日この頃。でも更新系やリンクとか入ってくるとつらいのでシンプルなエンテティの読み取り以上のことをしようとすると…。