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

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

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

エンティティの仕組み

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

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

Kotlin

@Entity
data class User(
    @PrimaryKey val id: Int,

    val firstName: String?,
    val lastName: String?
)

Java

@Entity
public class User {
    @PrimaryKey
    public int id;

    public String firstName;
    public String lastName;
}

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

Kotlin

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

Java

@Entity(tableName = "users")
public class User {
    @PrimaryKey
    public int id;

    @ColumnInfo(name = "first_name")
    public String firstName;

    @ColumnInfo(name = "last_name")
    public String lastName;
}

主キーを定義する

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

Kotlin

@PrimaryKey val id: Int

Java

@PrimaryKey
public int id;

複合主キーを定義する

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

Kotlin

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

Java

@Entity(primaryKeys = {"firstName", "lastName"})
public class User {
    public String firstName;
    public String lastName;
}

フィールドを無視する

デフォルトでは、Room はエンティティ内で定義されているフィールドごとに列を作成します。エンティティ内に永続化しないフィールドがある場合は、@Ignore を使用して対象フィールドにアノテーションを付けます。次のコード スニペットをご覧ください。

Kotlin

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

Java

@Entity
public class User {
    @PrimaryKey
    public int id;

    public String firstName;
    public String lastName;

    @Ignore
    Bitmap picture;
}

エンティティが親エンティティからフィールドを継承している場合、通常は @Entity 属性の ignoredColumns プロパティを使用する方が簡単です。

Kotlin

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

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

Java

@Entity(ignoredColumns = "picture")
public class RemoteUser extends User {
    @PrimaryKey
    public int id;

    public boolean hasVpn;
}

Room は、データベースのテーブル内の詳細情報を簡単に検索できるように、さまざまなタイプのアノテーションをサポートしています。アプリの minSdkVersion が 16 未満でなければ、全文検索を利用できます。

全文検索をサポートする

全文検索(FTS)を通じてデータベース情報に迅速にアクセスする必要があるアプリの場合、FTS3 または FTS4 の SQLite 拡張モジュールを使用した仮想テーブルで、エンティティをバックアップします。Room 2.1.0 以降で利用可能なこの機能を使用するには、対象エンティティに @Fts3 または @Fts4 のアノテーションを追加します。次のコード スニペットをご覧ください。

Kotlin

// Use `@Fts3` only if your app has strict disk space requirements or if you
// require compatibility with an older SQLite version.
@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 use this type and column name. */
    @PrimaryKey @ColumnInfo(name = "rowid") val id: Int,
    @ColumnInfo(name = "first_name") val firstName: String?
)

Java

// Use `@Fts3` only if your app has strict disk space requirements or if you
// require compatibility with an older SQLite version.
@Fts4
@Entity(tableName = "users")
public class User {
    // Specifying a primary key for an FTS-table-backed entity is optional, but
    // if you include one, it must use this type and column name.
    @PrimaryKey
    @ColumnInfo(name = "rowid")
    public int id;

    @ColumnInfo(name = "first_name")
    public String firstName;
}

テーブルが複数の言語のコンテンツをサポートしている場合は、languageId オプションを使用して、各行の言語情報を格納する列を指定します。

Kotlin

@Fts4(languageId = "lid")
@Entity(tableName = "users")
data class User(
    // ...
    @ColumnInfo(name = "lid") val languageId: Int
)

Java

@Fts4(languageId = "lid")
@Entity(tableName = "users")
public class User {
    // ...

    @ColumnInfo(name = "lid")
    int languageId;
}

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

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

FTS3 / FTS4 テーブル バックアップ型エンティティに対応していない SDK バージョンをサポートする必要があるアプリの場合は、データベース内の特定の列をインデックスに登録することで、クエリを高速化できます。エンティティにインデックスを追加するには、@Entity アノテーション内に indices プロパティを追加して、インデックスまたは複合インデックスに登録する列の名前をリストアップします。このアノテーション プロセスを実行するコード スニペットを以下に示します。

Kotlin

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

Java

@Entity(indices = {@Index("name"),
        @Index(value = {"last_name", "address"})})
public class User {
    @PrimaryKey
    public int id;

    public String firstName;
    public String address;

    @ColumnInfo(name = "last_name")
    public String lastName;

    @Ignore
    Bitmap picture;
}

データベース内の特定のフィールドやフィールド グループを一意にすることが必要となる場合があります。この一意性プロパティを適用するには、@Index アノテーションの unique プロパティを true に設定します。firstName 列と lastName 列に対して同一の値セットを持つ 2 つの行がテーブル内に存在しないようにするコードサンプルを以下に示します。

Kotlin

@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?,
    @Ignore var picture: Bitmap?
)

Java

@Entity(indices = {@Index(value = {"first_name", "last_name"},
        unique = true)})
public class User {
    @PrimaryKey
    public int id;

    @ColumnInfo(name = "first_name")
    public String firstName;

    @ColumnInfo(name = "last_name")
    public String lastName;

    @Ignore
    Bitmap picture;
}

AutoValue ベースのオブジェクトを含める

Room 2.1.0 以降では、@AutoValue を使用してアノテーションを付けることで、Java ベースの不変値クラスを、アプリのデータベース内のエンティティとして使用できます。この機能は特に、「エンティティの 2 つのインスタンスに関して、列に同じ値が格納されている場合は等しいと見なす」というケースで役立ちます。

@AutoValue アノテーションの付いたクラスをエンティティとして使用する場合、@PrimaryKey@ColumnInfo@Embedded@Relation を使用してクラスの抽象メソッドにアノテーションを付けることができます。ただし、このようなアノテーションを使用する場合は、メソッドの自動生成実装を Room が適切に解釈できるように、毎回 @CopyAnnotations アノテーションを含める必要があります。

Room がエンティティとして認識できる @AutoValue アノテーション付きクラスの例を次のコード スニペットに示します。

User.java

@AutoValue
@Entity
public abstract class User {
    // Supported annotations must include `@CopyAnnotations`.
    @CopyAnnotations
    @PrimaryKey
    public abstract long getId();

    public abstract String getFirstName();
    public abstract String getLastName();

    // Room uses this factory method to create User objects.
    public static User create(long id, String firstName, String lastName) {
        return new AutoValue_User(id, firstName, lastName);
    }
}