当您使用 Room 持久性库 存储应用数据时,您定义实体来表示要存储的对象。每个实体对应于关联的 Room 数据库中的一个表,并且每个实体实例表示对应表中的一行数据。
这意味着您可以使用 Room 实体定义您的 数据库模式,而无需编写任何 SQL 代码。
实体的结构
您将每个 Room 实体定义为一个用 @Entity
注释的类。Room 实体包含数据库中对应表中每一列的字段,包括构成 主键 的一个或多个列。
以下代码是一个简单实体的示例,它定义了一个 User
表,其中包含 ID、名字和姓氏的列
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 使用类名作为数据库表名。如果希望表具有不同的名称,请设置 tableName
属性 @Entity
注释。类似地,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
注释单个列。
Kotlin
@PrimaryKey val id: Int
Java
@PrimaryKey public int id;
定义复合主键
如果需要实体的实例由多个列的组合唯一标识,则可以通过在 @Entity
的 primaryKeys
属性中列出这些列来定义复合主键
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; }
当实体继承自父实体的字段时,通常使用ignoredColumns
属性(位于@Entity
注解中)会更容易。
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; }
有时,数据库中的某些字段或字段组必须是唯一的。您可以通过将unique
属性(位于@Index
注解中)设置为true
来强制执行此唯一性属性。以下代码示例防止表格包含两行具有相同firstName
和lastName
列值集的行。
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及更高版本中,您可以使用基于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); } }