この記事では、Roomを使ってSQLiteのデータベースの2つのテーブルをリレーションさせる内容を書いて行きます。

利用するSDKのクラスはRoomDatabaseというものがあり、それを利用していきます。

 

Roomの使い方については、別の記事MVVMモデルでRoomDatabaseによるSQLiteの操作とLiveDataでRecyclerViewに表示する仕組みでまとめているので、参考にしていただければと思います。

 

Roomでは、2つのテーブルをリレーションさせるというのは、2つのエンティティをリレーションさせるという事になります。

詳細については、Google Developersのオブジェクト間のリレーションを定義するを読み込むといいです。

ここでは、基本となる1対1のリレーションについて書いて行きたいと思います。

1.前提となるデータについて

GooglePlayストアでリリースしている「履歴が残るToDoリスト」では、以下のような画面とデータで、1つのセルに、ToDoのデータベーステーブルとLogのデータベーステーブルを読み込ませています。

1.1.画面

1.2.データベース設計

1.3.実際のデータ

上記のように、1つのToDoに対して、新規で作成→記載内容を修正→ToDoが完了という操作をした場合に、それぞれの操作時刻をlogとして保存しています。
そして、画面には、一番最後の操作を表示するようにしています。

2.リレーションを定義したクラスを定義する

todo_tableのエンティティであるToDoクラスとlog_tableのエンティティであるLogクラスが以下のように定義されている場合

@Entity(tableName = "todo_table")
public class ToDo {
    long todo_id;
    String contents;
    long latest_log_id;
}

@Entity(tableName = "log_table")
public class Log {
    long log_id;
    Date date;
    int operation;
}

この2つをリレーションを定義するToDoAndLogクラスを以下のように@Embeddedアノテーションを使って定義します。
@Embeddedを付けるのは、親テーブル側のToDoクラスです。

public class ToDoAndLog {
    @Embedded public ToDo toDo;
    @Relation( parentColumn = "latest_log_id", entityColumn = "log_id")
    public Log log;
}

3.Daoのメソッド定義に@Transactionアノテーションを付ける

ToDoのData Access ObjectであったToDoDaoのメソッドに@Transactionアノテーションを付加して、帰り値の型をToDoAndLogに変更します。

@Dao
public interface ToDoDao {
    @Transaction
    @Query("SELECT * FROM todo_table")
    LiveData<List<ToDoAndLog>> getToDoList();

以上で、2つのテーブルをリレーションさせる事ができました。
 
わざわざリレーションさせなくても、todo_tableとlog_tableを別々のトランザクションで読み出す処理を書くこともできるのですが、Roomによるデータベースアクセスはワーカースレッドからのアクセスが必須となるため、同期的に読み出す事ができず画面更新にずれが発生してしまいます。
なので、複数のテーブルを1つのトランザクションで読み出す必要があるの場合には、このような実装をする必要があります。
 

最後に、冒頭でも紹介しましたが

シンプル操作でやることの管理ができる「記録が残るToDoリスト」

 

 

Todoを登録したり、完了した日時を自動で記録して履歴として表示することができる便利な機能が特徴です。

無料で公開していますので、ぜひダウンロードして確認してみてください。