使用 Room 實體定義資料

使用 Room 持續性程式庫儲存應用程式的資料時,您可以定義實體來代表要儲存的物件。每個實體都會對應到相關 Room 資料庫中的一個資料表,而實體的每個例項則代表對應資料表中的一列資料。

這表示您不必編寫任何 SQL 程式碼,就可以使用 Room 實體定義資料庫結構定義

實體剖析

您可以將每個 Room 實體定義為已加上 @Entity 註解的類別。Room 實體包含資料庫中對應資料表內每個資料欄的欄位,包括構成主鍵的一或多個資料欄。

以下程式碼是簡單的實體範例,定義了內含 ID、名字和姓氏資料欄的 User 資料表:

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

   
val firstName: String?,
   
val lastName: String?
)
@Entity
public class User {
   
@PrimaryKey
   
public int id;

   
public String firstName;
   
public String lastName;
}

根據預設,Room 會使用類別名稱做為資料庫的資料表名稱。如果想讓資料表使用不同名稱,請設定 @Entity 註解的 tableName 屬性。同樣地,Room 預設會使用欄位名稱做為資料庫中的資料欄名稱。如果您想讓某個資料欄使用不同名稱,請為相關欄位加上 @ColumnInfo 註解,並設定 name 屬性。以下示範資料表及其資料欄的自訂名稱:

KotlinJava
@Entity(tableName = "users")
data class User (
   
@PrimaryKey val id: Int,
   
@ColumnInfo(name = "first_name") val firstName: String?,
   
@ColumnInfo(name = "last_name") val lastName: String?
)
@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 實體都必須定義主鍵 用於識別資料庫資料表中每個資料列的專屬 ID。最簡單的做法是使用 @PrimaryKey 為單一資料欄加上註解:

KotlinJava
@PrimaryKey val id: Int
@PrimaryKey
public int id;

定義複合式主鍵

如果需要利用多個資料欄的組合來識別實體的執行個體,建議您定義「複合式主鍵」,方法是在 @EntityprimaryKeys 屬性中列出這些資料欄:

KotlinJava
@Entity(primaryKeys = ["firstName", "lastName"])
data class User(
   
val firstName: String?,
   
val lastName: String?
)
@Entity(primaryKeys = {"firstName", "lastName"})
public class User {
   
public String firstName;
   
public String lastName;
}

忽略欄位

根據預設,Room 會為實體中定義的每個欄位建立一個資料欄。如果實體中有不想保留的欄位,您可以使用 @Ignore 加上註解,如以下程式碼片段所示:

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

   
public String firstName;
   
public String lastName;

   
@Ignore
   
Bitmap picture;

}

如果實體沿用父系實體的欄位,則使用 @Entity 屬性的 ignoredColumns 屬性通常比較簡單:

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

@Entity(ignoredColumns = ["picture"])
data class RemoteUser(
   
@PrimaryKey val id: Int,
   
val hasVpn: Boolean
) : User()
@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 註解,如以下程式碼片段所示:

KotlinJava
// 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?
)
// 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 選項來指定儲存各資料列語言資訊的資料欄:

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

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

Room 提供多種其他選項來定義受 FTS 支援的實體,包括結果排序、權杖化器類型以及當做外部內容管理的資料表。如要進一步瞭解這些選項,請參閱 FtsOptions 參考資料。

索引專用的資料欄

如果應用程式必須支援的 SDK 版本,不允許由 FTS3 或 FTS4 資料表支援的實體,您依然可以為資料庫中的特定資料欄建立索引,以加快查詢速度。如要為實體加入索引,請在 @Entity 註解中加入 indices 屬性,列出要在索引或複合式索引中加入的資料欄名稱。下列程式碼片段示範這項註解程序:

KotlinJava
@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?
)
@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,就能強制執行這個不重複屬性。下列程式碼範例可防止資料表出現兩個資料列,當中含有相同的 firstNamelastName 資料欄值組合:

KotlinJava
@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?
)
@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 以上版本中,您可以使用 Java 的不可變值類別 (也就是加上 @AutoValue 註解的類別),做為應用程式資料庫中的實體。當實體的兩個執行個體當中的資料欄含有相同的值時,這項支援尤其實用。

使用加上 @AutoValue 註解的類別做為實體時,您可以使用 @PrimaryKey@ColumnInfo@Embedded@Relation 為類別的抽象方法加上註解。不過,使用這些註解時,您必須每次都加入 @CopyAnnotations 註解,讓 Room 能夠正確解讀方法自動產生的實作項目。

下列程式碼片段是加上 @AutoValue 註解的類別範例,Room 會將此類別視為實體:

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);
   
}
}