LoginSignup
2
0

More than 5 years have passed since last update.

Android Roomでrailsのcreated_atみたいなことをする(Daoをラップする)

Last updated at Posted at 2019-03-17

Room Persistence Libraryを使用してデータを永続化しているのだが、Ruby on Railsのcreated_atのようなタイムスタンプを付ける必要があった。スマートな方法ではないものの、一応実現する方法を考えたのでメモっておく。

問題

公式ドキュメント通りに実装すると、DaoとDatabaseは次のような感じで定義することになると思う。

UserDao.kt
@Dao
interface UserDao {
    @Insert
    fun insert(user: User)
}
AppDatabase.kt
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

UserDaoinsertは実装を定義できないので、このままだとDaoを使用する側でinsertする前にcreated_atを設定してやらなければならない。たぶん次のような感じになるのかな。

Daoを使う側.kt
db.userDao().also { dao ->
    ...
    user.createdAt = LocalDateTime.now()
    dao.insert(user)
}

これだとDaoを使う側で毎回タイムスタンプを設定してやらなければならないし、何より設定漏れが発生する可能性がある。できれば、railsみたいに自動で設定してほしいところ。

解決方法

Dao#insertをフックできれば早いんだけど今の所そういったことはできないみたい・・・。仕方ないのでDaoのラッパーを作ってやって、常にラッパー経由でデータベースにアクセスするようにしてやる。

まずはDatabaseを変更して、自動生成されるDao_Implではなくラッパークラスのインスタンスを返すようにする。

AppDatabase.kt
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    protected abstract fun getUserDao(): UserDao
    fun userDao(): UserDao = UserDao.Wrapper(getUserDao())
}

UserDaoを返すabstractメソッドはprotectedにして外部からのアクセスを禁止する。代わりにuserDaoメソッドを公開して、こいつでWrapperクラスのインスタンスを返すようにする。

続いて、UserDaoの定義は次のような感じ。

UserDao.kt
@Dao
interface UserDao {
    @Insert
    fun insert(user: User)

    class Wrapper(private val dao: UserDao) : UserDao {
        override fun insert(user: User) {
            user.createdAt = LocalDateTime.now()
            dao.insert(user)
        }
    }
}

こうしておけば、常にDaoのWrapper経由でデータベースにアクセスすることになるので、createdAtの設定漏れは発生しない。

自動生成Dao_Implをコンポジションするので、タイムスタンプ周りの用件に限らず、色々と使いみちがあると思う。

※ 本記事ではcreatedAtにLocalDateTimeを使用していますが、TypeConverterに関する内容は省略しています

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0