Room エンティティを使用してデータを定義する

Room 永続ライブラリを使用してアプリのデータを保存する場合、保存するオブジェクトを表すようにエンティティを定義します。各エンティティは、関連付けられた Room データベース内のテーブルに対応し、エンティティの各インスタンスは、対応するテーブルのデータ行を表します。

Room エンティティを使用すると、SQL コードを記述せずにデータベース スキーマを定義できます。

エンティティの仕組み

各 Room エンティティは、@Entity アノテーションを付けたクラスとして定義します。Room エンティティには、データベース内の対応するテーブルの各列のプロパティが含まれます(主キーを構成する 1 つ以上の列など)。

次のコードは、ID、姓、名の列を持つ User テーブルを定義するエンティティの例です。

@Entity
data class User(
    @PrimaryKey val id: Int,
    val firstName: String,
    val lastName: String
)

デフォルトでは、Room はクラス名をデータベース テーブル名として使用します。テーブルに別の名前を付ける場合は、@Entity アノテーションの tableName プロパティを設定します。同様に、Room はデフォルトでプロパティ名をデータベースの列名として使用します。列に別の名前を付ける場合は、プロパティに @ColumnInfo アノテーションを追加し、name プロパティを設定します。次の例は、テーブルとその列のカスタム名を示しています。

@Entity(tableName = "users")
data class User(
    @PrimaryKey val id: Int,
    @ColumnInfo(name = "first_name") val firstName: String,
    @ColumnInfo(name = "last_name") val lastName: String
)

主キーを定義する

対応するデータベース テーブルの各行を一意に識別するには、各 Room エンティティの主キーを定義する必要があります。そのためには、@PrimaryKey で 1 つの列にアノテーションを付けます。

@PrimaryKey val id: Int

複合主キーを定義する

あるエンティティのインスタンスを複数の列の組み合わせで一意に識別する必要がある場合、@EntityprimaryKeys プロパティでそれらの列をリストして、複合主キーを定義できます。

@Entity(primaryKeys = ["firstName", "lastName"])
data class User(
    val firstName: String,
    val lastName: String
)

プロパティを無視

デフォルトでは、Room はエンティティ内で定義されているプロパティごとに列を作成します。Room がプロパティを永続化しないようにするには、@Ignore でアノテーションを付けます。

@Entity
data class User(
    @PrimaryKey val id: Int,
    val firstName: String,
    val lastName: String,
    @Ignore val picture: Bitmap? = null
)

エンティティが親エンティティからプロパティを継承している場合は、@Entity アノテーションの ignoredColumns プロパティを使用します。

open class User {
    var picture: Bitmap? = null
}

@Entity(ignoredColumns = ["picture"])
data class RemoteUser(
    @PrimaryKey val id: Int,
    val hasVpn: Boolean
) : User()

Room は、データベース テーブル内の詳細情報を検索できるさまざまなアノテーションをサポートしています。

全文検索をサポートする

高速な全文検索(FTS)が必要なアプリの場合は、仮想テーブルでエンティティをバックアップします。FTS3 または FTS4 SQLite 拡張機能、または FTS5 SQLite 拡張機能を使用します。

この機能を使用するには、エンティティに @Fts3@Fts4、または @Fts5 アノテーションを追加します。

// Use `@Fts3` only if your app has strict disk space requirements.
@Fts4
@Entity(tableName = "users")
data class User(
    // Specifying a primary key for an FTS-table-backed entity is optional,
    // but if you include one, it must an INTEGER type and column name "rowid".
    @PrimaryKey @ColumnInfo(name = "rowid") val id: Long,
    @ColumnInfo(name = "first_name") val firstName: String
)

FTS テーブルでデータベース情報がトークン化される方法をカスタマイズするには、tokenizer オプションを使用します。Room は、FtsOptions を通じて、TOKENIZER_SIMPLETOKENIZER_PORTERTOKENIZER_UNICODE61 などの組み込みトークナイザーをいくつか提供します。

@Fts4(tokenizer = FtsOptions.TOKENIZER_UNICODE61)
@Entity(tableName = "users")
data class User(
    @PrimaryKey @ColumnInfo(name = "rowid") val id: Long,
    @ColumnInfo(name = "first_name") val firstName: String
)

Room には、結果の順序化や、列からのインデックスの削除、外部コンテンツとして管理されるテーブルなど、FTS バックアップ型エンティティを定義するためのオプションが幅広く用意されています。これらのオプションの詳細については、FtsOptions リファレンスをご覧ください。

特定の列をインデックスに登録する

AndroidSQLiteDriver を使用していて、FTS3、FTS4、FTS5 テーブル バックアップ型エンティティに対応していない SDK バージョンをサポートする必要がある場合は、データベース内の特定の列をインデックスに登録することで、クエリを高速化できます。BundledSQLiteDriver を使用する場合、Room は Android SDK のバージョンに関係なく、すべての FTS バージョンをサポートします。

エンティティにインデックスを追加するには、@Entity アノテーションに indices プロパティを追加します。インデックスまたは複合インデックスに登録する列の名前をリストアップします。次のコード スニペットは、インデックスを追加する方法を示しています。

@Entity(indices = [Index(value = ["last_name", "address"])])
data class User(
    @PrimaryKey val id: Int,
    @ColumnInfo(name = "first_name") val firstName: String,
    @ColumnInfo(name = "last_name") val lastName: String,
    val address: String?,
)

データベース内の特定の列や列グループに一意の値を含める必要がある場合があります。この一意性を適用するには、@Index アノテーションの unique プロパティを true に設定します。次のコードサンプルは、この一意性を適用する方法を示しています。

@Entity(indices = [Index(value = ["first_name", "last_name"], unique = true)])
data class User(
    @PrimaryKey val id: Int,
    @ColumnInfo(name = "first_name") val firstName: String,
    @ColumnInfo(name = "last_name") val lastName: String,
)