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

かずきのBlog@hatena

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

Azure Mobile AppsでテーブルのクエリにIN句を使いたい

ODataはin句をサポートしてないらしい?ので出来ません。(完) こんな定義らしい。

filter = '$filter' EQ boolCommonExpr

boolCommonExpr = ( isofExpr 
                 / boolMethodCallExpr 
                 / notExpr  
                 / commonExpr
                   [ eqExpr 
                   / neExpr 
                   / ltExpr  
                   / leExpr  
                   / gtExpr 
                   / geExpr 
                   / hasExpr 
                   ]
                 / boolParenExpr
                 ) [ andExpr / orExpr ]

というのではあんまりなので代替案を。 渡された配列に対して1要素ずつ比較するのをORでつないでやればOKという方法で代替できます。 ただLINQでORをやるのは苦行で式木に踏み込まないといけません。

ということで、以下のようなTodoItemクラスに対して

using System;

namespace PrismMobileApp.Models
{
    public class TodoItem
    {
        public string Id { get; set; }

        public string Text { get; set; }

        public bool Complete { get; set; }

        public byte[] Version { get; set; }

        public DateTimeOffset? CreatedAt { get; set; }

        public DateTimeOffset? UpdatedAt { get; set; }
    }
}

IMobileServiceTable<TodoItem>型のTodoItemTableがある前提で引数で渡された文字列配列に対して一致するIDを持つTodoItemを抜き出す処理を書いてみましょう。

public Task<IEnumerable<TodoItem>> GetIds(params string[] ids)
{
    // x => false or id[0] == x.Id or id[1] == x.Id ...
    var x = Expression.Parameter(typeof(TodoItem), "x");
    Expression expression = Expression.Constant(false);
    foreach (var id in ids)
    {
        expression = Expression.OrElse(
            expression,
            Expression.Equal(Expression.Property(x, nameof(TodoItem.Id)), Expression.Constant(id)));
    }

    var lambda = Expression.Lambda<Func<TodoItem, bool>>(expression, x);
    return this.TodoItemTable.CreateQuery()
        .Where(lambda)
        .OrderBy(y => y.Text)
        .ToEnumerableAsync();
}

ということでこういう感じになります。式木の初歩的な感じですね。コメントに書いてあるような式を組み立ててます。式の中身を組み立てて最後にラムダ式にしてWhereに渡すという流れです。

では、よいLINQライフを。