Roomエンティティを使ったデータの定義 — Room Persistence Library(2)

Naoki Seto
Lionaroid
Published in
9 min readApr 2, 2018

Android Architecture Components 和訳

Room永続ライブラリを使用する場合、関連するフィールドのSetをエンティティとして定義します。

各エンティティに対してアイテムを保持するために、関連するデータベースオブジェクト内にテーブルが作成されます。

注意:アプリでエンティティを使用するには、アプリのbuild.gradleファイルに Architecture Components artifacts を追加します。

デフォルトでは、Roomはエンティティで定義されている各フィールドの列を作成します。エンティティに永続化したくないフィールドがある場合は、@Ignoreを使用してアノテーションを付けることができます。エンティティクラスは、Databaseクラスのエンティティ配列を使用して参照する必要があります。

次のコードスニペットは、エンティティを定義する方法を示しています。:

@Entity
class User {
@PrimaryKey
public int id;
public String firstName;
public String lastName;
@Ignore
Bitmap picture;
}

フィールドを永続化するには、Roomがそのフィールドにアクセスできる必要があります。フィールドをパブリックにすることもできますし、ゲッターとセッターを提供することもできます。getterメソッドとsetterメソッドを使用する場合、それらはRoomのJavaBeans規約に基づいていることに注意してください。

注意: エンティティは、空のコンストラクタ(対応するDAOクラスが各永続フィールドにアクセスできる場合)か、エンティティのフィールドの型と名前に一致する、型と名前を含むパラメータを持つコンストラクタを持つことができます。Roomは、フィールドの一部だけを受け取るコンストラクタのような、完全または部分的なコンストラクタを使用することもできます。

プライマリキーを使用する

各エンティティは、少なくとも1つのフィールドを主キーとして定義する必要があります。フィールドが1つしかない場合でもフィールドに @PrimaryKeyアノテーションを付ける必要があります。

また、Roomが自動的にIDをエンティティに割り当てる場合は、@PrimaryKeyのautoGenerateプロパティを設定できます。

エンティティに複合主キーがある場合は、次のコードスニペットに示すように、@EntityアノテーションのprimaryKeysプロパティを使用できます。:

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

デフォルトでは、Room はクラス名をデータベーステーブル名として使用します。テーブルの名前を変更する場合は次のコードスニペットに示すように、@EntityアノテーションのtableNameプロパティを設定します。

@Entity(tableName = "users")
class User {
...
}

警告: SQLiteのテーブル名は大文字と小文字を区別しません。

RoomはtableNameプロパティと同様に、フィールド名をデータベースの列名として使用します。列に別の名前を付ける場合は、次のコードスニペットに示すように、@ColumnInfoアノテーションをフィールドに追加します。

@Entity(tableName = "users")
class User {
@PrimaryKey
public int id;
@ColumnInfo(name = "first_name")
public String firstName;
@ColumnInfo(name = "last_name")
public String lastName;
@Ignore
Bitmap picture;
}

インデックスと一意性を注釈する

データへのアクセス方法に応じてクエリを高速化するために、データベースの特定のフィールドにインデックスを付けることができます。

エンティティにインデックスを追加するには、@Entityアノテーション内にindicesプロパティを含め、インデックスまたはコンポジットインデックスに含めたい列の名前をリストします。

次のコードスニペットは、このアノテーションプロセスを示しています。:

@Entity(indices = {@Index("name"),
@Index(value = {"last_name", "address"})})
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つの行が存在しないようにしています。:

@Entity(indices = {@Index(value = {"first_name", "last_name"},
unique = true)})
class User {
@PrimaryKey
public int id;
@ColumnInfo(name = "first_name")
public String firstName;
@ColumnInfo(name = "last_name")
public String lastName;
@Ignore
Bitmap picture;
}

オブジェクト間の関係を定義する

SQLiteはリレーショナルデータベースなので、オブジェクト間の関係を指定できます。

ほとんどのオブジェクト・リレーショナル・マッピング・ライブラリは、エンティティ・オブジェクトが互いに参照することを許可しますが、Room はこれを明示的に禁止します。

この決定の背後にある技術的な理由については、「Room がオブジェクト参照を許可しない理由を理解する」を参照してください。

直接関係を使用することはできませんが、Roomでは依然としてエンティティ間の外部キー制約を定義できます。

例えば、Bookという別のエンティティがある場合、次のコードスニペットに示すように @ForeignKeyアノテーションを使用してUserエンティティとの関係を定義できます。:

@Entity(foreignKeys = @ForeignKey(entity = User.class,
parentColumns = "id",
childColumns = "user_id")
)
class Book {
@PrimaryKey
public int bookId;
public String title; @ColumnInfo(name = "user_id")
public int userId;
}

外部キーは参照先のエンティティが更新された時に、何らかの指定の事象を起こすことができるため非常に強力です。

例えば、@ForeignKeyアノテーションにonDelete = CASCADEを含めることにより、対応するUserのインスタンスが削除された場合にSQLiteにユーザーのすべてのブックを削除するよう指示できます。

注意:SQLiteは@Insert(onConflict = REPLACE)を、単一のUPDATE操作の代わりにREMOVE操作とREPLACE操作のセットとして処理します。競合する値を置き換えるこの方法は、外部キー制約に影響する可能性があります。詳細については、ON_CONFLICT句の「SQLiteドキュメント」を参照してください。

ネストされたオブジェクトを生成する

場合によっては、オブジェクトに複数のフィールドが含まれていても、エンティティやプレーンな古いJavaオブジェクト(POJO)をデータベースロジック内にまとまった形で表現したいことがあります。

このような状況では、@Embeddedアノテーションを使用して、テーブル内のサブフィールドに分解するオブジェクトを表すことができます。

他の個々の列の場合と同様に、埋め込みフィールドをクエリできます。

例えば、User クラスには、street、city、state、postCodeという名前のフィールドの構成を表すAddress型のフィールドを含めることができます。作成された列をテーブルに個別に格納するには、次のコードスニペットに示すように、@Embeddedで注釈を付けたUserクラスのAddressフィールドを追加します。

class Address {
public String street;
public String state;
public String city;
@ColumnInfo(name = "post_code")
public int postCode;
}
@Entity
class User {
@PrimaryKey
public int id;
public String firstName; @Embedded
public Address address;

}

Userオブジェクトを表すテーブルには、id、firstName、street、state、city、post_codeという名前の列が含まれています。

注意:埋め込みフィールドには、他の埋め込みフィールドも含めることができます。

エンティティに同じ型の複数の埋め込みフィールドがある場合は、接頭辞プロパティを設定して各列を一意に保つことができます。

Roomは埋め込みオブジェクトの各列名の先頭に指定された値を追加します。

--

--

Naoki Seto
Lionaroid

AndroidがメインのIT技術者です。著書入門Androidアプリケーションテスト@オライリー社。