使用 Room 時,可以將相關的屬性定義為實體(entities)。
對於每個實體,將會創建一個資料表來保存項目在 Database 物件中,必須透過 Database 類別中的 entities 陣列來引用實體類別。
以下示範如何定義一個實體(entity)
@Entity public class User { @PrimaryKey public int id; public String firstName; public String lastName; }
為了保存屬性,Room 必須去存取它。可以透過將該屬性設定為 public 或提供 getter 和 setter 存取器。若是使用存取器必須注意該存取器必須符合 JavaBeans 的命名規則。
注意:
實體(Entity)可以有一個空構造函數(如果相應的 DAO 類別可以訪問每個持久化字段),或者一個構造函數,其參數包含與實體中的屬性匹配的類型和名稱。Room 也可以使用完整或部分構造函數,例如只接收某些屬性的構造函數。
Use a primary key
每個實體必須至少定義一個屬性作為主鍵。即使只有一個屬性,仍需要使用 @PrimaryKey 註釋來註釋該屬性。
此外,如果希望 Room 為實體分配自動 ID,可以設定 @PrimaryKey 的 autoGenerate 屬性。
如果實體具有複合主鍵,則可以使用 @Entity 註釋的 primaryKeys 屬性,如以下代碼段所示:
@Entity(primaryKeys = {"firstName", "lastName"}) public class User { public String firstName; public String lastName; }
Room 預設使用類別名稱作為資料表名稱。如果希望資料表使用不同的名稱,可以設定 @Entity 註釋的 tableName 屬性,如以下代碼段所示:
@Entity(tableName = "users") public class User { // ... }
注意:
資料表名稱是區分大小寫的
類似於 tableName,Room 使用屬性名稱作為資料庫中的列名稱。如果希望列具有不同的名稱,請將 @ColumnInfo 註釋加到屬性中,如以下代碼段所示:
@Entity(tableName = "users") public class User { @PrimaryKey public int id; @ColumnInfo(name = "first_name") public String firstName; @ColumnInfo(name = "last_name") public String lastName; }
Ignore fileds
預設情況下,Room 會為實體中定義的每個屬性都創建一列。如果實體具有不想保存的屬性,則可以使用 @Ignore 對其進行註釋,如以下代碼段所示:
@Entity public class User { @PrimaryKey public int id; public String firstName; public String lastName; @Ignore Bitmap picture; }
如果實體從另一個實體(父實體)繼承屬性,則通常使用 @Entity 屬性的 ignoredColumns:
@Entity(ignoredColumns = "picture") public class RemoteUser extends User { @PrimaryKey public int id; public boolean hasVpn; }
Provide table search support
Room 支持多種類型的註釋,可以更輕鬆地搜索資料表中的詳細信息。除非應用程序的 minSdkVersion 小於 16,否則請使用全文搜索(full-text search)。
Support full-text search
如果應用程序需要通過全文搜索(FTS)快速訪問數據庫信息,就讓實體由使用 FTS3 或 FTS4 SQLite 擴展模塊的虛擬表支持。
要使用全文搜索,必須在 Room 2.1.0 及更高版本,請將 @ Fts3 或 @ Fts4 註釋添加到給定實體,如以下代碼段所示:
// 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; }
注意:啟用 FTS 的資料表必須使用 INTEGER 類型的主鍵和列名”rowid”。如果 FTS 資料表支持的實體定義主鍵,則它必須使用該類型和列名稱。
如果資料表支持多種語言的內容,請使用 languageId 選項指定存儲每行語言信息的列:
@Fts4(languageId = "lid") @Entity(tableName = "users") public class User { // ... @ColumnInfo(name = "lid") int languageId; }
Room 提供了其他幾個用於定義FTS支持的實體選項,包括結果排序(result ordering),tokenizer 類型(tokenizer types)和作為外部內容管理的資料表。有關這些選項的更多詳細信息,請參閱 FtsOptions 參考。
Index specific columns
如果應用程序必須支持不允許使用 FTS3 或 FTS4 資料表支持實體的 SDK 版本,仍然可以索引數據庫中的某些列以加快查詢速度。
要向實體添加索引,請在 @Entity 註釋中包含 indices 屬性,列出要包含在索引或複合索引中的列的名稱。如下所示
@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 列的相同值集:
@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; }
Include AutoValue-based objects
注意:
這個特性只用於 java-based entities,不支援 Kotlin。
在 Room 2.1.0 及更高版本中,可以使用基於 Java 的不可變值類(使用 @AutoValue 進行註釋)作為數據庫中的實體。
如果實體的兩個實例的列包含相同的值,則此支持特別有用。
使用帶 @AutoValue 註釋的類別作為實體時,可以使用 @PrimaryKey,@ColumnInfo,@ Embedded 和 @Relation 註釋類別的抽象方法。但是,在使用這些註釋時,每次都必須包含 @CopyAnnotations 註釋,以便 Room 可以正確解釋方法的自動生成實現。
以下代碼段顯示了一個使用 @AutoValue 註釋類別的示例,Room 將其識別為實體:
@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); } }
Define relationships between objects
由於 SQLite 是關係數據庫,因此可以指定物件之間的關係。儘管大多數對象關係映射庫允許實體對象相互引用,但 Room 明確禁止這樣做。即使不能使用直接關係,Room 仍允許在實體之間定義外鍵約束。
例如,如果有另一個名為 Book 的實體,可以使用 @ForeignKey 註釋定義其與 User 實體的關係,如以下代碼段所示:
@Entity(foreignKeys = @ForeignKey(entity = User.class, parentColumns = "id", childColumns = "user_id")) public 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)作為一組 REMOVE 和 REPLACE 操作處理,而不是單個 UPDATE 操作。這種替換衝突值的方法可能會影響外鍵約束。
Create nested objects
有時候希望將實體或 POJO 表達為資料庫邏輯中的一個整體,即使該物件包含多個屬性。
在這些情況下,可以使用 @Embedded 註釋來表示要分解到資料表內子字屬性的物件。然後,可以像查找其他單個列一樣查詢嵌入屬性(Embedded filed)。
例如,User 類別可以包含 Address 類別的屬性,而 Address 也有其屬性為 street,city,state 和 postCode 屬性。
User.java
@Entity public class User { @PrimaryKey public int id; public String firstName; @Embedded public Address address; }
Address.java
public class Address { public String street; public String state; public String city; @ColumnInfo(name = "post_code") public int postCode; }
然後,表示 User 物件的資料表包含具有以下名稱的列:id,firstName,street,state,city 和 post_code。
注意:
嵌入屬性(Embedded filed)可以再包含其它嵌入屬性(Embedded filed)
如果實體具有多個相同類型的嵌入屬性,則可以通過設置 prefix 屬性使每個列保持唯一。然後,Room 將提供的值添加到嵌入屬性中每個列名稱的開頭。
Article Comments