【Android】DBFlowの基本的な使い方

DBFlowを使用してみたため、基本的な使い方をまとめておきます。(ver 4.0.0-beta5)

特徴

  1. AnnotationでModelの定義
  2. Modelは継承しなくても使用できるし、BaseModelの継承でModel#save()もできる
  3. ModelClass_Tableが自動生成され、ModelClass_Table.column_nameで各Columnにアクセスできる
  4. SQLらしい書き方

面倒なところ

  • Columnの追加などの変更にMigrationが必要

1. AnnotationでModelの定義

ModelはAnnotationで設定ができます。

@Table(database = AppDatabase.class, name = "table_name")
public class Hello{
    @Unique
    @PrimaryKey(autoincrement = true)
    public int id;

    @Column
    public String title;

    @Column(name = "world_id")
    public int worldId

    @Column(name = "created_at")
    public Date createdAt;
}

@Columnを記述すると、そのフィールドがColumnになります。 SQLiteでのColumn名をフィールドと違うものにする場合はname=xxxを設定します。

2. Modelは継承しなくても使用できるし、BaseModelの継承でModel#save()もできる

継承しない場合のINSERT/UPDATEは後述。
ModelはBaseModelを継承することでModel#save()ができるようになります。

public class Hello extends BaseModel{ ... }
...
hello.save();

3. Model_Tableが自動生成され、Model_Table.column_nameで各Columnにアクセスできる

WHEREを記述する場合、Modelから生成されたModel_Tableを使用して記述します。 文字列ではないため、コード補完が有効です。

WHERE id=1

.where(Hello_Table.id.eq(1));

4. SQLらしい書き方

SELECT

このようなSQLに対し、

SELECT * FROM Hello WHERE id=1

DBFlowではこのように記述します。

SQLite.select()
    .from(Hello.class)
    .where(Hello_Table.id.eq(1)); //=> Where<Hello>

1つ取得

where.querySingle(); //=> Hello

Listで取得

where.queryList(); //=> List<Hello>

Count

countの場合は少し特殊でselectCountOfを使用します。

SQLite.selectCountOf()
    .from(Hello.class)
    .where(Hello_Table.world_id.eq(worldId));
    .count(); //=> long

INSERT/UPDATE

INSERT/UPDATEは2種類の方法があります。

BaseModelの継承あり

BaseModelを継承した場合は、前述の通り、Model#save()で行います。

hello.save();
BaseModelの継承なし

継承しなくて済むならJavaのclassの制約に苦しまなくて済むためこちらを使用しています。 ただ、insert/updateを真面目に記述するのも面倒なため、 できれば上述のModel#save()のような方法の方が望ましく思います。

その場合、FlowManagerからAdapterを取得して、

ModelAdapter<Hello> adapter = FlowManager.getModelAdapter(Hello.class);

insertや

long id = adapter.insert(hello);

updateを行うことで

adapter.update(hello);

BaseModelを継承しなくてもsave()と同様のことができます。

DELETE

DELETEはSELECTとほぼ同様です。

SQLite.delete()
    .from(Hello.class)
    .where(Hello_Table.id.eq(1))
    .execute();

面倒なところ

仕方のないことかもしれませんが、Columnの追加などの変更の際にMigrationが必要です。

Migration

Columnの追加

HelloモデルにworldのColumnを追加する場合は、ModelにColumnを追加し、

public class Hello{
    ...

    @Column
    public int world;
}

MigrationをDatabaseクラスに記述します。

@Migration(version = 2, database = AppDatabase.class)
public static class Migration2 extends AlterTableMigration<Hello>{
    public Migration2(Class<Hello> table){ super(table); }

    @Override
    public void onPreMigrate() {
        addColumn(SQLiteType.INTEGER, Hello_Table.world.toString());
    }
}

その他

SELECT/INSERTが速い

天下一「AndroidのORM」武道会(2015年版)の速さランキングで上位にランクインしています。

GitHubのStar

2017年1月現在のStarの数です

所感

今回は速さランキングを参考にSQLiteの中から上記の選択肢に絞り、
速さ/安定/コードの書き方/学習コストといった点から最終的にDBFlowにしました。
見送った主な理由は以下の通りです。

  • greenDAO
    • generatorの記述が面倒
  • ActiveAndroid
    • ManifestにModelの記述が必要、GitHubの更新が途絶えている
  • Orma
    • やり方が悪いのかColumnを追加後に動かなくなった

参考