2014/12/06
PureJavaでAndroidのSQLite
Android で SQLite を使うときに結構冗長になるので何とかならないかと考えてみた。
Android 向けの O/R マッパーもぼちぼち出てきているようだけど そもそも Android でそんなに大規模なテーブル構成を使うことも無いので XML とかでテーブル定義書かされるのもウザかったりする。
なので目指すのは標準の Java だけでシンプルに SQLite を扱う方法。
- 1つのクラスで閉じている。
- テーブル生成、挿入、更新、削除、検索ができる。
- カラム名の定義(テーブル定義)は一ヶ所で済む。
- 定義したカラム名は eclipse の補間やリファクタが効く。
- コード量が少なく見通しが効く。
- 将来的に複雑な SQL が使いたくなっても耐えられる。
以上の要件を満たせる用に考えたテンプレがこれ。
package sample;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class SQLiteSample extends SQLiteOpenHelper {
static final String DB_NAME = "sample.db";
static final int VERSION = 100;
public interface Column {
public String name();
public String type();
}
// テーブル定義
private static final String SAMPLE_TABLE = "SAMPLE_TABLE";
public enum SampleCols implements Column {
_ID("integer primary key autoincrement"),
FIRST_NAME("text"),
SECOND_NAME("text");
// --- 以下、定形 (enumは継承が出来ないので) ---
private String mType;
private String mWhere;
SampleCols(String type) {
mType = type;
mWhere = name() + "=?";
}
// @formatter:off
public String type() {return mType;}
public String where() {return mWhere;}
public long getLong(Cursor cursor) {return cursor.getLong(cursor.getColumnIndex(name()));}
public int getInt(Cursor cursor) {return cursor.getInt(cursor.getColumnIndex(name()));}
public String getString(Cursor cursor) {return cursor.getString(cursor.getColumnIndex(name()));}
public void put(ContentValues values, long val) {values.put(name(), val);}
public void put(ContentValues values, int val) {values.put(name(), val);}
public void put(ContentValues values, String val) {values.put(name(), val);}
// @formatter:on
}
private SampleBean toBean(Cursor cursor) {
SampleBean data = new SampleBean(
SampleCols._ID.getLong(cursor),
SampleCols.FIRST_NAME.getString(cursor),
SampleCols.SECOND_NAME.getString(cursor)
);
return data;
}
private ContentValues fromBean(SampleBean bean) {
ContentValues values = new ContentValues();
SampleCols._ID.put(values, bean.getId());
SampleCols.FIRST_NAME.put(values, bean.getFirstName());
SampleCols.SECOND_NAME.put(values, bean.getSecondName());
return values;
}
SQLiteSample(Context context) {
super(context, DB_NAME, null, VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(getCreateTableDDL(SAMPLE_TABLE, SampleCols.values()));
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DELETE TABLE " + SAMPLE_TABLE + ";");
onCreate(db);
}
public SampleBean query(long id) {
SQLiteDatabase db = getReadableDatabase();
Cursor cursor = db.query(SAMPLE_TABLE, null, SampleCols._ID.where(), toArgument(id), null,null,null);
if (!cursor.moveToNext()) return null;
return toBean(cursor);
}
public long insert(SampleBean bean) {
SQLiteDatabase db = getWritableDatabase();
long id = db.insert(SAMPLE_TABLE, null, fromBean(bean));
return id;
}
public long update(SampleBean bean) {
SQLiteDatabase db = getWritableDatabase();
long id = db.update(SAMPLE_TABLE, fromBean(bean), SampleCols._ID.where(), toArgument(bean.getId()));
return id;
}
public long delete(SampleBean bean) {
SQLiteDatabase db = getWritableDatabase();
long id = db.delete(SAMPLE_TABLE, SampleCols._ID.where(), toArgument(bean.getId()));
return id;
}
private String[] toArgument(long id) {
return new String[] { Long.toString(id) };
}
private String getCreateTableDDL(String table, Column[] columns) {
StringBuilder sbuf = new StringBuilder();
sbuf.append("CREATE TABLE ").append(table).append('(');
for (Column column : columns) {
sbuf.append(column.name()).append(' ').append(column.type()).append(',');
}
sbuf.setLength(sbuf.length() - 1);
sbuf.append(");");
return sbuf.toString();
}
}
enum に継承機能が無いのが辛い。
ちなみに ContentProvider にしている例はこちら
この投稿へのコメント

コメント・フォーム