Adobe AIRで作るデスクトップアプリケーション

第15回 ローカルデータベースの利用

この記事を読むのに必要な時間:およそ 5 分

データベースの作成

AIRランタイムにはSQLiteというオープンソースのデータベース機能が組み込まれており,標準的なSQLを使ってローカルデータを管理できます。ファイルAPIでもローカルファイルの読み書きは可能ですが,例えばアドレス帳のように大量のデータを保存してランダムに検索したい場合などはデータベースの方が適しています。

データベースは単一のローカルファイルを使用します。このファイルには可搬性があり,好きな場所に保存できます。実際に作成してみましょう。

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="openDB()">
  <mx:Script>
    <![CDATA[
      private function openDB():void {
        var db:File = File.desktopDirectory.resolvePath("sample.db");
        var conn:SQLConnection = new SQLConnection();
        conn.addEventListener(SQLEvent.OPEN, openHandler);
        conn.addEventListener(SQLErrorEvent.ERROR, errorHandler);
        conn.openAsync(db);
      }
      private function openHandler(e:SQLEvent):void {
        trace("DBをオープンしました");
      }
      private function errorHandler(e:SQLErrorEvent):void {
        trace(e.error.message);
      }
    ]]>
  </mx:Script>
</mx:WindowedApplication>

上記のコードを実行すると,デスクトップにsample.dbというファイルが作成されます。これがデータベースファイルです。ここで行っているのはデータベースをオープンする処理です。データベースを使用するときは,毎回このようにSQLConnectionオブジェクトを作成し,openAsync()メソッドでオープンする必要があります。ファイルの指定にはFileオブジェクトを使います。指定のファイルが存在しないときは自動的に作成されます。ファイル名は拡張子も含めて任意で構いません。ファイルを指定しない場合はメモリ内にデータベースが作成されます。データベースを使い終わったらclose()メソッドでクローズします。

なお,openAsync()の代わりにopen()を使う方法もあります。openAsync()の場合はその後の処理が非同期となり,open()の場合は同期処理となります。同期処理はコードの流れを追いやすい等のメリットがありますが,扱うデータ量によっては他の処理を止めてしまうため,基本的には非同期処理を使ったほうが無難でしょう。

SQLの実行

データベースに対する操作はSQLで行います。SQLを実行するにはSQLStatementオブジェクトを使います。次のコードはテーブルを作成するサンプルです。データベースsample.dbをオープンして,2つのカラムfoodとpriceを持つテーブルmenuを作成しています。

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="openDB()">
  <mx:Script>
    <![CDATA[
      private var _conn:SQLConnection;
      private function openDB():void {
        var db:File = File.desktopDirectory.resolvePath("sample.db");
        _conn = new SQLConnection();
        _conn.addEventListener(SQLEvent.OPEN, openHandler);
        _conn.addEventListener(SQLErrorEvent.ERROR, errorHandler);
        _conn.openAsync(db);
      }
      private function openHandler(e:SQLEvent):void {
        createTable();
      }
      private function errorHandler(e:SQLErrorEvent):void {
        trace(e.error.message);
      }
      private function createTable():void {
        var sql:SQLStatement = new SQLStatement();
        sql.sqlConnection = _conn;
        sql.text = 
        "CREATE TABLE IF NOT EXISTS menu (" + 
        "  food TEXT," + 
        "  price NUMERIC" + 
        ")";
        sql.addEventListener(SQLEvent.RESULT, resultHandler); 
        sql.addEventListener(SQLErrorEvent.ERROR, errorHandler); 
        sql.execute();
      }
      private function resultHandler(e:SQLEvent):void {
        trace("テーブル作成済み");
      }
    ]]>
  </mx:Script>
</mx:WindowedApplication>

上のサンプルではcreateTable()メソッド内でSQLを実行しています。SQLStatementオブジェクトのsqlConnectionプロパティには実行対象のデータベースを指定します。値はSQLConnectionオブジェクトです。その上でtextプロパティにSQL文を設定し,execute()メソッドを呼び出すことでSQLが実行されます。正しく実行された場合はSQLEvent.RESULTイベント,エラーが発生した場合はSQLErrorEvent.ERRORイベントが送出されます。

レコードの操作結果

レコードの挿入や抽出等の操作を行った場合も,処理が正しく完了したときはSQLEvent.RESULTイベントを受け取ります。このタイミングでSQLStatementオブジェクトのgetResult()メソッドを呼び出すと処理結果を調べられます。次のコードはレコードを1件追加する例です。

private var _conn:SQLConnection;
private var _sql:SQLStatement;
/* データベースへの接続処理等は省略 */
private function insertRecords():void {
        _sql = new SQLStatement();
        _sql.sqlConnection = _conn;
        _sql.text = "INSERT INTO menu (food, price) VALUES ('牛丼', 280)";
        _sql.addEventListener(SQLEvent.RESULT, insertResultHandler);
        _sql.execute();
}
private function insertResultHandler(e:SQLEvent):void {
        var result:SQLResult = _sql.getResult();
        trace(result.lastInsertRowID);
}

コードから分かるように,getResult()メソッドの戻り値はSQLResultオブジェクトです。SQLResultオブジェクトにはいくつかのプロパティがあります。lastInsertRowIDプロパティは,最後に追加したレコードのIDを返します。テーブルに整数値型のプライマリキーが1つ定義されていればその値が使われますが,それ以外の場合はデータベースが自動で生成するユニークIDが使われます。

次のコードはpriceカラムが100以下のレコードを抽出する例です。

private var _conn:SQLConnection;
private var _sql:SQLStatement;
/* データベースへの接続処理等は省略 */
private function selectRecords():void {
        _sql = new SQLStatement();
        _sql.sqlConnection = _conn;
        _sql.text = "SELECT * FROM menu WHERE price <= 100";
        _sql.addEventListener(SQLEvent.RESULT, selectResultHandler);  
        _sql.execute();
}
private function selectResultHandler(e:SQLEvent):void {
        var result:SQLResult = _sql.getResult();
        var records:Array = result.data;
        if (records != null) {
                trace(records.length + "件ヒットしました");
                for each (var item:* in records) {
                        trace(item.food, item.price);
                }
        } else {
                trace("ヒットなし");
        }
}

今度はSQLResultオブジェクトのdataプロパティを取得しています。これは抽出したレコードの配列です。各要素はカラム名をプロパティとするObjectオブジェクトです。レコードが1件も一致しなかった場合,dataプロパティはnullになります。

著者プロフィール

タナカヤスヒロ

早稲田大学卒業後,DTP業務を経てマルチメディア系制作会社へ。Macromedia Directorにのめり込む。フリーランスとなりFlashにシフトしてからもデスクトップ絡みの仕事が絶えず,Apolloにも勝手に縁を感じている。現在株式会社antsに所属。ants Lab.にも記事を上げている。

URLhttp://labs.anthill.jp/

著書

コメント

コメントの記入