Azure Blob Storage のクエリでプロパティがnullのエンティティを検索する

Azure.Data.Tables の TableClient を使って、プロパティが null のエンティティを検索しようと思いましたが、その方法がわからずに悩んだのでメモしておきます。

先に結論

Odata の $filter でも同様に使えるテクニックかと思います。

$filter=not(Hogehoge ne '')

これで null のプロパティを検索できます。

プロパティがnullのエンティティを検索できない件

Azure Table Storage に nullable なプロパティがあるオブジェクトを記録しようとしていました。

例えばこんな感じに、恋人の ID を nullable にしたとします。

using Azure;
using Azure.Data.Tables;


public class Person : ITableEntity
{
    public Person() { }
    public Person(int id, string name, int? loverId = null)
    {
        Id = id; 
        Name = name;
        LoverId = loverId;
        PartitionKey = id.ToString();
        RowKey = "__PERSON__";  // 思いつかないので決め打ち
    }
    public int Id { get; set; }
    public string Name { get; set; }

    // nullable な恋人 ID
    public int? LoverId { get; set; }

    public string PartitionKey { get; set; }
    public string RowKey { get; set; }
    public DateTimeOffset? Timestamp { get; set; }
    public ETag ETag { get; set; }
}

public class Program
{

    static async Task Main()
    {
        var tableClient = new TableClient("<ConnectionStrings>", "Person");

        await tableClient.CreateIfNotExistsAsync();

        var persons = new Person[] 
        {
            new Person(1, "太郎", 4),
            new Person(2, "次郎"),
            new Person(3, "花子", 5),
            new Person(4, "加代子", 1),
            new Person(5, "小春", 3)
        };

        foreach (var person in persons)
        {
            await tableClient.AddEntityAsync(person);
        }

    }
}

これを実行すると、以下のようにエンティティが追加されます。

次郎さんだけ “独り” ですねw ()
なんか百合が発生してますがサンプルなので

で、そのあと

“独り” を探そうとしたときに躓きました。

Azure.RequestFailedException: 'One of the request inputs is not valid.

というエラーが。

飛ばしたクエリは愚直に

LoverId eq null

です。

プロパティがnullのエンティティを検索する方法

意味わかんないのでいろいろ試した感じ、

var filter = "LoverId eq null"; // Azure.RequestFailedException: 'One of the request inputs is not valid.
var filter = "LoverId eq ''"; // 検索該当なし (プロパティがstring 型でも同様)
var filter = "not(LoverId ne '')"; // これだとうまくいく

上の最後の行のフィルタで動くようです。

以下に検証用のコードの全体を示します。

using Azure;
using Azure.Data.Tables;


public class Person : ITableEntity
{
    public Person() { }
    public Person(int id, string name, int? loverId = null)
    {
        Id = id; 
        Name = name;
        LoverId = loverId;
        PartitionKey = id.ToString();
        RowKey = "__PERSON__";  // 思いつかないので決め打ち
    }
    public int Id { get; set; }
    public string Name { get; set; }

    // nullable な恋人 ID
    public int? LoverId { get; set; }

    public string PartitionKey { get; set; }
    public string RowKey { get; set; }
    public DateTimeOffset? Timestamp { get; set; }
    public ETag ETag { get; set; }
}

public class Program
{

    static async Task Main()
    {
        var tableClient = new TableClient("<ConnectionStrings>", "Person");

        var filter = "LoverId eq null"; // Azure.RequestFailedException: 'One of the request inputs is not valid.
        //var filter = "LoverId eq ''"; // 検索該当なし (プロパティがstring 型でも同様)
        //var filter = "not(LoverId ne '')"; // これだとうまくいく

        // クエリ
        var queryResults = tableClient.QueryAsync<Person>(filter);

        // 取得したものを一覧する
        await foreach (var entity in queryResults)
        {
            Console.WriteLine($"{entity.Id}:{entity.Name}");
        }
    }
}

なぜ not(hoge ne ”) でプロパティがnullのエンティティを検索できるのか

正直分かりません。

おそらく、Azure Table Storage は 内部でエンティティを JSON に近い形式で保存していて、null のオブジェクトを Add しようとするとき、TableClient.AddEntity() が null のプロパティを書き出さないせいで、プロパティを検索しようとしたときに、そんなものねえよってなるんですかね

でも、エラーが One of the request inputs is not valid. だし、なんかクエリ自体が無効な記述なようなきもする。単に無いプロパティでフィルタしようとしてるから駄目だぜ!ってこと???

Odata詳しい方いたら教えてほしいです。

コメント

タイトルとURLをコピーしました