テスターですが何か?

ホビープログラマ略してHPです

AzureTableStorageでサポートされないLINQメソッド

with one comment

AzureTableStorageへのアクセスはLINQがサポートされています、が、いくつかのメソッドはサポートされていません。今回のエントリーではよく使われるであろうLINQメソッドがAzureTableStorageでサポートされているかどうかを確認してきます。前回のエントリーで作成したソース、テーブルをもとに確認を行います。

 

1.OrderBy

よく使われるであろうNo.1だと思います。以下のようなLINQ構文です、まぁ王道ですよね。

var q = from t in context.CreateQuery<SampleModels>(TableName)
        orderby t.Key
        select t;

var q1 = q.ToList();

このLINQ構文を実行すると、例外(DataServiceQueryException)が発生します。重要なことをさらっと言いますが、AzureTableStorageに対してOrderByを実行することはできません

image

InnerExceptionを確認すると、「The requested operation is not implemented on the specified resource.」とのことです。つまり、「そんなオペレーション実装してねーよ m9(^Д^)プギャー」ってことです。

AzureTableStorageはPartitionKeyとRowKeyの昇順で自動的に並び替えられます、そのため、データを登録する際に意図したソート順になるように値を設定する必要があります。また、PartitionKeyとRowKeyは文字列型でなければならないため、数値を登録する場合は0埋めしないと意図したソート順になりません。どうしても降順で並び替えたい場合は、9の補数で登録する必要があります。(12→87)

もうひとつ、ソートする方法があります。System.Data.Services.Client.DataServiceQueryのOrderByを使用するのではなく、ListのOrderByを使用する方法です。(表現が間違っているかもしれません)つまり、以下のようにソースを書き換えます。

var q = from t in context.CreateQuery<SampleModels>(TableName)
            select t;

var q1 = q.ToList().OrderBy(p => p.Key);

AzureTableStorageからデータを取得する際に並び替えるのではなく、データを取得後にメモリ上で並び替える方法です。やや処理は非効率になりますが、これで意図通りに自由自在にソートができると思います。

 

2.Count

次は定番その2、Countです。取り上げるということは、サポートされていません。

var q = (from t in context.CreateQuery<SampleModels>(TableName)
            select t).Count();

上記のようなどこにでもありそうなLINQ構文を実行すると、例外(DataServiceQueryException)が発生します。Messageプロパティを確認すると「Server encountered an internal error. Please try again after some time.」と、思わせぶりなメッセージですが、何度実行しても例外が発生します。(Please try againなんて思わせぶりなセリフを吐くなよ)じゃあどうしたらいいかというと、メモリ上で実行すればいいんです。

これでデータ件数のカウントを行うことができます。

var q = from t in context.CreateQuery<SampleModels>(TableName)
            select t;
var q1 = q.ToList().Count;

 

3.Max/Min

次はMax/Minです、もちろんサポートされていません。以下のような構文はきっぱりと「NotSupportedException」が発生します、Messageプロパティもストレートに「メソッド ‘Max’ はサポートされていません。」となります。

var q = from t in context.CreateQuery<SampleModels>(TableName)
        select t;
var q1 = q.Max(p=>p.Key);

解決方法は...はいはいはい、メモリ上で集計すればいいんでしょ?

var q = from t in context.CreateQuery<SampleModels>(TableName)
             select t;
var q1 = q.Max.ToList().(p=>p.Key);

 

4.First/Last

個人的によく使うメソッドです。もちろんサポートされていませんと思いきや、「Firstはサポートされているけど、Lastはサポートされていません」 このようなFirstメソッドは普通に実行可能です。

var q = (from t in context.CreateQuery<SampleModels>(TableName)
             select t).First();

しかし、同じようにLastを記述すると、NotSupportedExceptionが発生し「メソッド ‘Last’ はサポートされていません。」となります。これまでと同じようにメモリ上で実行する必要があります。

var q = (from t in context.CreateQuery<SampleModels>(TableName)
             select t).Last();

 

5.Take/Skip

First/Lastを試したなら、Take/Skipを試してみましょう。結論は「Takeはサポートされているけど、Skipはサポートされていません」 このようなTakeメソッドは普通に実行可能です。

var q = (from t in context.CreateQuery<SampleModels>(TableName)
              select t).Take(10);

しかし、Skipを記述するとDataServiceQueryExceptionが発生します。Skipメソッドの使用なのかどうかわかりませんが、Skipメソッド実行箇所ではなくforeachなどでコレクションにアクセスして時点で例外が発生します。

var q = (from t in context.CreateQuery<SampleModels>(TableName)
              select t).Skip(800);

じゃあどうしたらいいかというと、やっぱりメモリ上で実行するしかありません。

var q = from t in context.CreateQuery<SampleModels>(TableName)
            select t;
var q1 = q.ToList().Skip(800);

 

6.Distinct

これで最後です、Distinctもサポートされていません。Skipと動揺にメソッドを実行行ではなく結果のコレクションにアクセスする箇所でDataServiceQueryExceptionが発生します。以下のような記述は例外が発生します。なので、いったんListに変換してからDistinctを実行する必要があります。

var q = (from t in context.CreateQuery<SampleModels>(TableName)
             select t).Distinct();

 

今回のエントリーは以上です、ソースはこちらからダウンロード可能です。SampleRepositoryクラスのCheckLinqメソッドに今回確認したLinq構文が全部記述されています。

Written by david9142

2011年6月18日 @ 10:45 PM

カテゴリー: WindowsAzure

Tagged with , ,

コメント / トラックバック1件

Subscribe to comments with RSS.

  1. 遅延評価という点では変わりませんが(それと挙動的には内部で全部列挙されるのもそうですね)
    幾つかはAsEnumerableを使うのはどうでしょう。
    Countだけが目的だったりの場合は、わざわざList化して捨てるよりも良い結果が得られそうです。

    var count = context.CreateQuery(TableName).AsEnumerable().Count();
    var ordered = context.CreateQuery(TableName).AsEnumerable().OrderBy(p => p.Key).ToArray();

    neuecc

    2011年6月19日 at 2:02 AM


コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。