package com.android_mvc.framework.db.dao; import java.util.ArrayList; import java.util.List; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import com.android_mvc.framework.common.FWUtil; import com.android_mvc.framework.db.DBHelper; import com.android_mvc.framework.db.entity.BaseLogicalEntity; /** * SELECT時の検索条件を保持し,検索を実行するクラス。 * @author id:language_and_engineering * */ public class Finder<T extends BaseLogicalEntity<T>> { // NOTE: 本当は,Rails3のArelを模倣できたら最高なんだが。。。。 private DBHelper helper; // SELECT時の検索条件 private String selection = ""; private String orderDescription; private int offsetNum = -1; private int limitNum = -1; public Finder(DBHelper helper) { this.helper = helper; } /** * WHERE句をセット */ public Finder<T> where( String selection ) { this.selection = selection; return this; } /** * ORDER BY句をセット */ public Finder<T> orderBy(String orderDescription) { this.orderDescription = orderDescription; return this; } /** * OFFSET句をセット */ public Finder<T> offset(int offsetNum) { this.offsetNum = offsetNum; return this; } /** * LIMIT句をセット */ public Finder<T> limit(int limitNum) { this.limitNum = limitNum; return this; } /** * セット済みの検索条件で,全件検索を実行する。 */ public List<T> findAll( Class<T> entity_class ) { // NOTE: なぜ,Tを受け取っておきながら,こんな引数が必要になるのか? // それは,Javaではジェネリクスの型パラメータでnewできないから。 // なんとも冗長。美しくない。でもユーザ側の記述量の削減にはなるので,甘受すべし…。 // http://www.ne.jp/asahi/hishidama/home/tech/java/generics.html#h3_new // http://blog.isocchi.com/2009/02/new.html // LIMIT句を構築 String limitClause = null; if( offsetNum > 0 ) { limitClause = "" + offsetNum; } if( limitNum > 0 ) { if( limitClause != null ) { limitClause += ","; } else { limitClause = ""; } limitClause += "" + limitNum; } FWUtil.d("DB接続をオープンします。"); SQLiteDatabase db = helper.getReadableDatabase(); List<T> result_list = new ArrayList<T>(); try{ // NOTE: インスタンスメソッドを呼びたいだけのためのオブジェクト。 // Class<T>は不可視だし,Tはnewできんし,裏技的にインスタンス生成。 // table名取得プロセスが,staticだとうまく共有できないのがつらいところ。 T dummy_entity = entity_class.newInstance(); FWUtil.d("クエリを発行します。"); Cursor c = db.query( dummy_entity.tableName(), dummy_entity.columns(), selection, null, null, null, orderDescription, limitClause ); // http://d.hatena.ne.jp/shimooka/20110428/1303972105 FWUtil.d("全件の結果を読み取ります。"); while( c.moveToNext() ) { // カーソル(物理値)から,論理エンティティを構築する T entity = entity_class.newInstance().logicalFromPhysical(c); // 結果に格納 result_list.add(entity); } FWUtil.d("クエリへの参照を破棄します。"); c.close(); } catch (InstantiationException e) { FWUtil.e( e.toString() ); } catch (IllegalAccessException e) { FWUtil.e( e.toString() ); } finally { db.close(); } FWUtil.d("全件検索結果の件数:" + result_list.size() ); return result_list; } }