ボクココ

個人開発に関するテックブログ

GreenDAOを使ってみた

GreenDaoはいわばAndroidSQLiteのORM。
デフォルトのSQLiteの操作は、使いにくいしお決まりの作法をコピペしたりと色々ひどいので、こういうのはフレームワークに任せたいところ。

環境作り

jarの用意

greendaogreendao-generatorfreemarker.jarをそれぞれ取ってくる

generator プロジェクト作成

新規→Javaプロジェクト
外部ライブラリーで先ほどとってきたgreendao-generatorとfreemarker.jarをライブラリーとして追加。
パッケージとクラスを適当に作る。ここにテーブルスキーマを記述する。


public static void main(String[] args) throws Exception {
Schema schema = new Schema(3, "{com.aaaa.dao}");

addNote(schema);
addCustomerOrder(schema);

new DaoGenerator().generateAll(schema, "../DaoExample/src-gen");
}

private static void addNote(Schema schema) {
Entity note = schema.addEntity("Note");
note.addIdProperty();
note.addStringProperty("text").notNull();
note.addStringProperty("comment");
note.addDateProperty("date");
}

private static void addCustomerOrder(Schema schema) {
Entity customer = schema.addEntity("Customer");
customer.addIdProperty();
customer.addStringProperty("name").notNull();

Entity order = schema.addEntity("Order");
order.setTableName("ORDERS"); // "ORDER" is a reserved keyword
order.addIdProperty();
Property orderDate = order.addDateProperty("date").getProperty();
Property customerId = order.addLongProperty("customerId").notNull().getProperty();
order.addToOne(customer, customerId);

ToMany customerToOrders = customer.addToMany(order, customerId);
customerToOrders.setName("orders");
customerToOrders.orderAsc(orderDate);
}

みたいに作る。
addNote()はシンプルなテーブル。
addCustomerOrder()はcustomer と order が1対多の関係になっていて、それを2つ一緒に定義している。idは指定しなくても勝手に作られる。

このGeneratorJavaプロジェクトは1個だけ作っておけば、あとは次からAndroidアプリ作るときもパッケージ名変えればいいだけだから使いまわせる。

作ったエンティティに対して、スーパークラスやインタフェースをインプリメントさせたい場合もあるよね。その時はentity#setSuperclass()とかentity#implementsInterface()とかも用意されているので使えそう。

generateAllをする前に、対象プロジェクトにソースフォルダーを追加しておく必要がある。今回の例ではDaoExampleプロジェクトにsrc-genを追加。

そんじゃジェネレート!

さっきの.javaを実行。

無事できました。うひゃひゃ
パスとかで躓いている方は、generateAllの引数にフルパス指定してみてください。

プログラム書いてみる

ちょっとね、、初期化が面倒。DevOpenHelperはアップデート時にテーブルドロップするから注意。


SQLiteDatabase db = new DaoMaster.DevOpenHelper(this, "notes-db", null).getWritableDatabase();
DaoSession daoSession = new DaoMaster(db).newSession();

NoteDao noteDao = daoSession.getNoteDao();

//インサート
Note note = new Note(null, noteText, comment, new Date());
noteDao.insert(note);
//デリート
long key = 1;
noteDao.deleteByKey(id)

// リード
List notes = noteDao.loadAll();
Note note = noteDao.loadByRowId(1);

//アップデート
Note note = new Note(1, noteText, comment, new Date());
noteDao.update(note);

//こんな見たことあるようなやり方もできる
List joes = noteDao.queryBuilder()
.where(Properties.text.eq("Hoge"))
.orderAsc(Properties.date)
.list();

 
list()以外にもrazyList()ってのもあるみたい。
「エンティティがメモリの要望に応じてロードされる。一回リストの中に要素がアクセスされたら、今後の為にキャッシュされる。必ず閉じないといけない。」って書いてあった。
Androidでスレッドを使っていると、SQLiteに対して複数のスレッドから同時にアクセスすると例外が発生して落ちる、みたいなのに悩まされることがよくある。これもGreenDAOは考慮されているみたいで、forCurrentThread()ってのをうまく使えば、利用側はスレッドとか心配しなくてバンバンアクセスできるらしい。内部読んでみたら、ThreadLocalを継承しているみたい。ここら辺ちょっと気になる。

Memo

Proguard


-keep public class my.dao.package.models.** {
public static ;
}



興味持ったら、
http://greendao-orm.com/
まで。
「道」のファビコンがいい味出してます。