Android で使える ORM、Requery を試してみた

Android で使える ORM である Requery のセットアップとお試しです。

はじめに

Android の ORM は百花繚乱の様相を呈しており、それぞれ一長一短あるので選ぶのが難しいのですが、最近出てきた Requery が良さそうだったので、少し使ってみました。

ちなみに、Requery が良さそうに思えた点は以下のとおりです(重要度順):

  • RxJava のサポートがしっかりしていそう
  • マイグレーション機能
  • ドキュメントが比較的揃っている
  • Kotlin 用の機能

なお、ここで使った Requery のバージョンは 1.4.0 です。

また、サンプルコードは Kotlin です。

インストール

app/build.gradle に以下の設定を入れます:

kapt {
    generateStubs = true  // for Requery
}

def rxjava2_version = "2.1.3"
def rxandroid_version = "2.0.1"
def requery_version = "1.4.0"

dependencies {
    .....
    compile "io.reactivex.rxjava2:rxjava:$rxjava2_version"
    compile "io.reactivex.rxjava2:rxandroid:$rxandroid_version"
    compile "io.requery:requery:$requery_version"
    compile "io.requery:requery-android:$requery_version"
    compile "io.requery:requery-kotlin:$requery_version"
    kapt "io.requery:requery-processor:$requery_version"
}

各バージョンは、現時点の最新版を指定しています。

初期化

初期化処理として、Application の派生クラスに以下の設定を入れます:

class App : Application() {

    val DB_FILE_NAME = "app.db"
    val DB_VERSION = 1

    val entityStore: KotlinReactiveEntityStore<Persistable> by lazy {
        val source = DatabaseSource(this, Models.DEFAULT, DB_FILE_NAME, DB_VERSION)
        source.setTableCreationMode(TableCreationMode.DROP_CREATE)  // マイグレーション
        KotlinReactiveEntityStore<Persistable>(KotlinEntityDataStore(source.configuration))
    }

    override fun onCreate() {
.....

各パラメータは必要に応じて変更してください。

なお、Models については、最初は参照エラーが発生します。

モデルを追加した後でビルドすると自動生成されるため、その後、参照を追加します。

モデルの定義

Requery の場合、モデルは抽象クラスかインターフェースで定義します。また、Kotlin の場合はデータクラスでも定義できます。

ここでは、抽象クラスで定義してみます:

@Entity
@Table(name = "users")
abstract class BaseUser {
    @Key
    @JvmField
    var id: Long = 0

    @JvmField
    @Column(name = "display_name")
    var displayName: String = ""
}

抽象クラスの名前は、接頭辞として BaseAbstract を付けます。そうすると、接頭辞のないクラスがサブクラスとして生成されます。

なお、現時点のバージョンでは、各カラム定義の前に @JvmField を付けなければなりません。

これを付けないと、Entity field cannot be private というエラーになります。

Ref.

select

試しに Activity で select してみます:

class MainActivity : AppCompatActivity() {
    lateinit var entityStore: KotlinReactiveEntityStore<Persistable>
    val userNameView: TextView by bindView(R.id.userNameView)
    .....
    override fun onCreate(savedInstanceState: Bundle?) {
        .....
        entityStore = (application as App).entityStore
        showUserName()
        .....
    }
    .....
    fun showUserName() {
        val user = entityStore.select(User::class).get().firstOrNull()
        userNameView.text = user?.displayName ?: "(unknown)"
    }
}

ここでは単純にするため、同期的に処理してみましたが、実アプリでは Rx で非同期的に処理した方が良いです。

Ref.

Rx

データ変更があったら自動的に select する処理を Rx で実装してみようとしたのですが、少しロジックを実装する必要があるようです:

How to observe table changes wothout select or count? · Issue #535 · requery/requery

Rx のサポートはまだ不十分かな。。。

ということで、Requery については、ここで一旦保留にしておきます。

エラー: クラスcom.example.app.models.Userが重複しています

いろいろ試行錯誤している途中で上記のようなエラーが発生しました。

その場合は、Android Studio の Build メニューから「Clean Project」すると解消しました。