Android Kotlin基礎講座 06.1: Roomデータベースを作成する

タスク:DAOを作成する

このタスクでは、データアクセスオブジェクト(DAO)を定義します。Androidにおいて、DAOはデータベースの挿入、削除、更新用の便利なメソッドを提供しています。

Roomデータベースを使う際には、コード内でKotlin関数を定義、呼び出しすることによってデータベースのクエリを行います。これらのKotlin関数はSQLクエリに位置します。DAO内にアノテーションを使って定義し、Roomが必要なコードを作成します。

DAOはデータベースにアクセスするためのカスタムインターフェースの定義と捉えてください。

一般的なデータベースの操作用に、Roomライブラリは@Insert、@Delete、@Updateといった便利なアノテーションを用意しています。その他全てについては、@Queryアノテーションがあります。SQLiteにサポートされているどんなクエリでも書くことができます。

加えて、Android Studioでクエリを作成する際、コンパイラーはSQLクエリに構文エラーがないかまでチェックしてくれます。

sleep-trackerデータベースを扱う上では以下のことができる必要があります。

  • 新しい夜を挿入する。
  • 既に存在している夜の終了時間と睡眠の質を更新
  • 指定した夜をキーをもとにして取得
  • 画面に表示するために全ての夜を取得
  • 最新の夜を取得
  • データベース内の全ての実体を削除

ステップ1:SleepDatabase DAOを作成する

  1. databaseパッケージのSleepDatabaseDao,ktを開いてください。
  2. interface SleepDatabaseDaoが@Daoによってアノテーションされていることを確認してください。全てのDAOは@Daoというキーワードでアノテーションされる必要があります。
@Dao
interface SleepDatabaseDao {}
  1. インターフェースのボディ内に@Insertアノテーションを追加してください。その下にEntityクラスであるSleepNightを引数にとるinsert()関数を追加してください。

    これだけです。これでRoomがSleepNightをデータベースに挿入するために必要なコードを全て生成してくれます。Kotlinコードからinsert()を呼び出すと、Roomは実体をデータベースに挿入するためのSQLクエリを実行します。(呼び出したい関数をなんでも呼び出せます)
@Insert
fun insert(night: SleepNight)
  1. SleepNight用のupdate()関数と@Updateアノテーションを追加してください。更新される実体は渡されたキーと同じキーをもつ実体です。実体の一部、または全てのプロパティを更新することができます。
@Update
fun update(night: SleepNight)

残りの機能には便利なアノテーションがありませんので、@Queryアノテーションを使ってSQLiteクエリを書いてあげる必要があります。

  1. get()関数と@Queryアノテーションを追加してください。get()関数はLong型のkeyを引数にとり、nullがありえるSleepNightを返します。パラメータに関するエラーが表示されます。
@Query
fun get(key: Long): SleepNight?
  1. クエリはstring型のパラメータとしてアノテーションに渡されます。@QueryにSQLクエリを表すString型のパラメータを追加してください。
  • daily_sleep_quality_tableから全てのカラムを選択します。
  • WHEREでnightIdが引数keyに合致した部分を抽出します。

    :keyを確認してください。関数の引数を参照させるためにコロンノーテーション(:)を使います。
("SELECT * from daily_sleep_quality_table WHERE nightId = :key")
  1. さらに@Queryをclear()関数と共に追加してください。daily_sleep_quality_tableから全てのデータを削除するSQLiteクエリを追加してください。このクエリはテーブル自体を削除するものではありません。

    @Deleteアノテーションは一つのアイテムを削除します。削除する夜のリストを渡すこともできます。これの欠点はテーブルに何があるのか知ったり、フェッチする必要があることです。@Deleteアノテーションは特定の実体を削除するのには素晴らしい機能ですが、テーブルから全ての実体を削除するのには不向きで、非効率的です。
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()
  1. さらに@QueryをgetTonight()関数と共に追加してください。この関数ではSleepNightをnull許容で返すようにします。そうすることでテーブルが空の場合でもエラーが起きません。(テーブルは一番初めとデータがクリアされた直後は空になっています)

    データベースから”tonight”を取得するために、nightIdを基に降順で並び替えられた結果のリストの最初の要素を返すSQLiteクエリを書いてください。一つだけ要素を返すためにはLIMIT 1を使ってください。
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1")
fun getTonight(): SleepNight?
  1. 最後に@QueryをgetAllNights()関数と共に追加してください。
  • SQLiteクエリに降順に並べられたdaily_sleep_quality_tableから全てのカラムを返すようにしてください。
  • getAllNight()関数はSleepNight実体のリストをLiveDataとして返すようにしてください。RoomはLiveDataを常に更新してくれています。つまり明示的にこのデータを取得するのは一度だけでよいということです。
  • androidx.lifecycle.LiveDataからLiveDataをインポートする必要があるかもしれません。
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC")
fun getAllNights(): LiveData<List<SleepNight>>
  1. ここまででアプリに目に見える変化はないはずです。エラーがないか、アプリを起動して確認してください。