2011年3月4日

ODataObjCを使ったiOSアプリを作ってみた(3)~ODataObjCによるCRUD

前回で、Azure Tableに対してODataObjCライブラリを使う準備ができました。いよいよ本番ということで、ODataObjCを用いたAzure Tableに対するCRUD処理について書いていきます。
記事中で使用しているソースコードは、作成したiOSアプリ「Cloud BookShelf」のものです。記事内ではソースコードを切りだしているため分かりにくい部分もあると思いますが、後ほどソース全部を公開しますのでそっちも合わせて参考にしてください。

エンティティの定義

まず最初に、Azure Tableに保存するエンティティを表すクラスとして、Bookクラスを作成します。
Book.h
   1: #import <Foundation/Foundation.h>
   2: #import "Azure/TableEntry.h"
   3:  
   4: @interface Book : TableEntry {
   5:     NSString *title;
   6:     NSString *author;
   7:     NSString *rate;
   8: }
   9:  
  10: @property (nonatomic, retain) NSString *title;
  11: @property (nonatomic, retain) NSString *author;
  12: @property (nonatomic, retain) NSString *rate;
  13:  
  14: @end
このように、エンティティが保持する情報をプロパティとして定義します。(Book.mはそれぞれ定義したpropertyをsynthesizeするだけ)

エンティティの追加

そして定義したエンティティをAzure Table上に追加します。
このメソッドが定義されたクラスでは、tableContextプロパティとしてObjectContextを保持していて、そのObjectContextを使ってエンティティを保存しています。(学習用のアプリなので強制的にParitionKey・RowKeyを再設定していますが、既存のエンティティをパラメータにしても新規追加されてしまうため、ちゃんと使いたいときはその辺りも考えないといけない)
   1: - (Book *) insert:(Book *)aBook {
   2:     NSLog(@"Insert");
   3:     [aBook setPartitionKey:[[UIDevice currentDevice] uniqueIdentifier]]; //PartitionKeyとしてiPhoneのUDIDを使う
   4:     [aBook setRowKey:[ODataGUID GetNewGuid]]; //RowKeyはGUIDにしておく
   5:     
   6:     [self.tableContext addObject:@BOOK_ENTITY_NAME object:aBook];
   7:     
   8:     if ( !self.enabledBatch ){
   9:         //バッチモードでない場合だけSaveChangesする
  10:         [self commit];
  11:     }
  12:     
  13:     return aBook;
  14: }

エンティティの検索

次にAzure Table上に保存されたエンティティの検索です。以前この記事で書いたとおりオリジナルのODataObjCでは日本語をパラメータに使えません。(まぁ、自力でURLエンコードさせればいいんですが。。。)
そこで、その記事中に載せた簡易クエリビルダを利用します。
   1: - (NSArray *) find:(NSString *)aQuery {
   2:     NSString *deviceId = [[UIDevice currentDevice] uniqueIdentifier];
   3:     
   4:     //デフォルトでPartitionKeyによる絞り込みを入れておく
   5:     NSString *q = [NSString stringWithFormat:@"PartitionKey eq '%@'%@%@", deviceId, ( aQuery != @"" ? @" and " : @"" ), aQuery];
   6:     
   7:     DataServiceQuery *query = [[DataServiceQuery alloc] initWithUri:@BOOK_ENTITY_NAME objectContext:self.tableContext];
   8:     [query filter:q];
   9:     
  10:     QueryOperationResponse *response = [query execute];
  11:     NSArray *result = [response getResult];
  12:     
  13:     NSLog(@"Query Result");
  14:     for(Book *r in result){
  15:         NSLog(@"Book(title=%@, author=%@, rate=%@) PK:%@ RK:%@ Timestamp:%@", r.title, r.author, r.rate, r.PartitionKey, r.RowKey, r.Timestamp);
  16:     }
  17:     
  18:     return result;
  19: }
  20:  
  21: - (NSArray *) findByQueries:(Queries *)aQueries {
  22:     return [self find:aQueries.filterString];
  23: }
呼び出し側はこんな感じ。
   1: Queries *aQueries = [Queries with:@"title" eq:text];
   2: self.books = [bookService findByQueries:aQueries];

エンティティの更新

次のエンティティの更新はエンティティを追加とほぼ同じ。PartitionKeyとRowKeyは既に付いているためセットしないのと追加するときはaddObjectだったのをupdateObjectにするだけ。
ただし要注意は、updateObjectの引数にしているエンティティはそのObjectContextで追跡されていなければならないこと。具体的には、同じObjectContextで追加したものや検索して取得したものしか更新はできない
ソースコードはこんな感じ。
   1: - (Book *) update:(Book *)aBook {
   2:     [self.tableContext updateObject:aBook];
   3:     
   4:     if ( !self.enabledBatch ){
   5:         //バッチモードでない場合だけSaveChangesする
   6:         [self commit];
   7:     }
   8:     
   9:     return aBook;
  10: }

エンティティの削除

最後にエンティティの削除ですが、これも追加や更新と同じようなコーディングでOKです。addObjectやupdateObjectをdeleteObjectに書き換えるだけ。
ただし、更新と同様にObjectContextで追跡済みのエンティティしか削除出来ません
   1: - (void) remove:(Book *)aBook {
   2:     [self.tableContext deleteObject:aBook];
   3:     if ( !self.enabledBatch ){
   4:         [self commit];
   5:     }
   6: }
こんな感じで削除できます。

0 件のコメント:

コメントを投稿