当您使用 Room 持久性库存储应用数据时,可以定义实体来表示要存储的对象。每个实体都对应于关联的 Room 数据库中的一个表,并且实体的每个实例都表示相应表中的一行数据。
使用 Room 实体,您无需编写任何 SQL 代码即可定义数据库架构。
实体详解
您可以将每个 Room 实体定义为带有 @Entity 注解的类。Room 实体包含数据库中相应表中的每一列的属性,包括构成主键的一个或多个列。
以下代码是一个实体的示例,该实体定义了一个 User 表,其中包含 ID 列、名字列和姓氏列:
@Entity data class User( @PrimaryKey val id: Int, val firstName: String, val lastName: String )
默认情况下,Room 将类名称用作数据库表名称。如果您希望表具有不同的名称,请设置 @Entity 注解的 tableName 属性。同样,Room 默认使用属性名称作为数据库中的列名称。如果您希望列具有不同的名称,请将 @ColumnInfo 注解添加到该属性并设置 name 属性。以下示例展示了表及其所含列的自定义名称:
@Entity(tableName = "users") data class User( @PrimaryKey val id: Int, @ColumnInfo(name = "first_name") val firstName: String, @ColumnInfo(name = "last_name") val lastName: String )
定义主键
您必须为每个 Room 实体定义一个主键,以唯一标识相应数据库表中的每一行。为此,请使用 @PrimaryKey 为单个列添加注解:
@PrimaryKey val id: Int
定义复合主键
如果您需要通过多个列的组合对实体实例进行唯一标识,则可以通过列出 @Entity 的 primaryKeys 属性中的以下列定义一个复合主键:
@Entity(primaryKeys = ["firstName", "lastName"]) data class User( val firstName: String, val lastName: String )
忽略属性
默认情况下,Room 会为实体中定义的每个属性创建一个列。
如需防止 Room 持久保留某个属性,请使用 @Ignore 对其进行注释:
@Entity data class User( @PrimaryKey val id: Int, val firstName: String, val lastName: String, @Ignore val picture: Bitmap? = null )
如果实体从父实体继承属性,请使用 @Entity 注解的 ignoredColumns 属性:
open class User { var picture: Bitmap? = null } @Entity(ignoredColumns = ["picture"]) data class RemoteUser( @PrimaryKey val id: Int, val hasVpn: Boolean ) : User()
提供表搜索支持
Room 支持多种注解,可让您搜索数据库表中的详细信息。
支持全文搜索
如果您的应用需要快速全文搜索 (FTS),请使用虚拟表为您的实体提供支持。使用 FTS3 或 FTS4 SQLite 扩展或 FTS5 SQLite 扩展。
如需使用此功能,请向实体添加 @Fts3、@Fts4 或 @Fts5 注解。
// Use `@Fts3` only if your app has strict disk space requirements. @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 an INTEGER type and column name "rowid". @PrimaryKey @ColumnInfo(name = "rowid") val id: Long, @ColumnInfo(name = "first_name") val firstName: String )
如需自定义 FTS 表中数据库信息的令牌化方式,请使用 tokenizer 选项。Room 通过 FtsOptions 提供多个内置分词器,包括 TOKENIZER_SIMPLE、TOKENIZER_PORTER 和 TOKENIZER_UNICODE61:
@Fts4(tokenizer = FtsOptions.TOKENIZER_UNICODE61) @Entity(tableName = "users") data class User( @PrimaryKey @ColumnInfo(name = "rowid") val id: Long, @ColumnInfo(name = "first_name") val firstName: String )
Room 提供了用于定义由 FTS 支持的实体的其他几个选项,包括结果排序、从列中移除索引以及作为外部内容管理的表。如需详细了解这些选项,请参阅 FtsOptions 参考文档。
将特定列编入索引
如果您使用的是 AndroidSQLiteDriver,并且需要支持不允许使用由 FTS3、FTS4 或 FTS5 表支持的实体的 SDK 版本,您仍可以将数据库中的某些列编入索引,以加快查询速度。如果您使用 BundledSQLiteDriver,无论 Android SDK 版本如何,Room 都支持所有 FTS 版本。
如需为实体添加索引,请在 @Entity 注释中添加 indices 属性。列出要包含在索引或复合索引中的列名称。以下代码段展示了如何添加索引:
@Entity(indices = [Index(value = ["last_name", "address"])]) data class User( @PrimaryKey val id: Int, @ColumnInfo(name = "first_name") val firstName: String, @ColumnInfo(name = "last_name") val lastName: String, val address: String?, )
有时,数据库中的某些列或列组需要包含唯一值。如需强制实施此唯一性,请将 @Index 注释的 unique 属性设为 true。以下代码示例展示了如何强制执行此唯一性:
@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, )