かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

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