Archive for 2009/9/4
あまりにも久しぶり(2か月)で自分でもどこまで記述したか忘れてしまったので、再度、過去を整理。
ちょっと、ZIPライブラリにどっぷりつかりすぎてしまいました。
過去、どのような記事を書いたかといえば、
flex:DataGrid sqlを使ってdataProviderを自作する ( Part 1 )
flex:DataGrid sqlを使ってdataProviderを自作する ( Part2: 大きなデータを扱う時にページングって本当に必要ですか?)
ただ、内容的には、Part1の続きです。(Part2はどちらかといえば、番外編コラム的内容です。)
気を取り直して、DataGridのdataProviderを作成するために必要なのは、
- TableCollectionView
- ICollectionViewを継承したクラス。Array(ArrayListのほうが正しい)に対するArrayCollectionの関係のクラスです
- TableList
- こちらは、データそのものを表すクラス。今度はArrayCollecitonに対するArray(ArrayList)に相当するクラスです。
- get length():int – プロパティとなっていますが、getterなので・・
- getItemAt():Object
- getItemIndex():Object
の2つのクラスです。
そうそう、思い出してきました。
ArrayとArrayCollectionの関係も参考になるので、この関係がわからない方は、こちらも読んでください。
TableListのクラスはIListインターフェースを実装する必要があります。
このインターフェースのすべてを実装する必要はありません。
そもそも大量なデータの参照の場合には、通常、登録処理はドラッグ&ドロップなどでやるということはあまりないはずです。
したがって、ここのインターフェースを使って登録や・更新されるようなことは今回考えません。
では、実装するメソッドは何があるの・・・・って
たったこれだけです。
もちろん、IListのインターフェースを満たす必要がありますので、それ以外のメソッドはnullを返すようなメソッドを実装しておいてください。
(本当は、ランタイムエラーを返すようにしておいたほうがいいかもしれません。はっきり使えないことがわかりますので・・・)
さて、length()では
SELECT count(*) as count FROM [テーブル名];
のようなSQLを実行すればいいわけですので、TableListクラスでは逆にSQLが実行できるような環境設定が必要というわけなので、
package com.coltware.commons.db
{
public class TableList extends EventDispatcher implements IList{
private var _conn:SQLConnection = null;
private var _tableName:String;
public function set sqlConnection(conn:SQLConnection):void{
this._conn = conn;
}
public function set tableName(name:String):void{
this._tableName = name;
}
}
}
のように、SQLの接続とテーブル名だけでも外部から設定しておけるようにしておけば当面は間に合うと思います。
上のコードにIListのインターフェースを満たす実装をしていきます。
以下が、lengthのgetterメソッドです。
public function get length():int
var stmt:SQLStatement = new SQLStatement();
stmt.sqlConnection = this._conn;
stmt.text = "SELECT count(*) as count FROM " + this._tableName;
stmt.execute();
var result:SQLResult = stmt.getResult();
if( result != null && result.data != null ){
var retObj:Object = new Object();
var size:int = result.data.length;
if(size > 0 ){
return result.data[0]["count"];
}
}
return 0;
}
ここで、0以上が帰れば、次に呼ばれるのは getItemAtです。
public function getItemAt(index:int, prefetch:int=0):Object
{
var sql:String = "SELECT * FROM " + this._tableName + " LIMIT 1 OFFSET " + index;
// 後は、length()のメソッドを参考に実装をしてください。
}
のようになります。
ここで、SQLとして、「あれ?」と思う部分は・・・・
そう、ソート部分がないのです。とりあえず、ちょっと話がややこしくなるので、今のところはここは無視しください。
(後で、ソートについても実装していきます。)
また、1行、1行、SELECTするのってどうなの?と思う方もいるかもしれませんが、JOINなどをしないのであれば毎回このように取ってきても問題ないと思います。
だって、表示されている部分しか取ってきませんし・・・
(気になる方は、キャッシュ機能(ページング機能)を実装してください。)
後は、getItemIndexですが、ただし、ちょっと疑問?な点があります。
オブジェクトからそのオブジェクトが何番目のオブジェクトなのか?ってどうやってわかるの?
だいたい、何番目ってどこを基準に?
って話です。
しかし、そもそも、getItemAtで、「n番目のデータをください!」ってお願いされているのですから、
ここで、このオブジェクトはn番目ってしるしをつけておくとよいでしょう。
そして、基準もここである前提(ソートが関係)のもと聞いているのですから、問題ないと思います。
私はそのために管理オブジェクトを作るのも何なので、
public function getItemAt(index:int, prefetch:int=0):Object
{
: ( 省略 )
var result:SQLResult = stmt.getResult();
if( result != null && result.data != null ){
var obj:Object = result.data[0];
obj['_internal_index'] = index;
return obj;
}
return null;
}
のように、オブジェクト自身に新たにプロパティを設けて、ここに保存してしまいます。
まず、_internal_indexなんているカラムは作らないと思います。
これで、
public function getItemIndex(item:Object):int
{
return item['_internal_index'];
}
のようになるわけです。
さて、これで使わないが宣言だけ必要なメソッドを実装すれば完成です。
次回は、TableCollectionViewを実装、そして次に、ソート部分の対応をしていきます。

