当您使用 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 必须拥有该字段的访问权限。您可以通过将某个字段设为公开或为其提供 getter 和 setter 方法,确保 Room 能够访问该字段。
默认情况下,Room 将类名称用作数据库表名称。如果您希望表具有不同的名称,请设置 @Entity 注解的 tableName 属性。同样,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;
}
注意:SQLite 中的表和列名称不区分大小写。
定义主键
每个 Room 实体都必须定义一个主键,用于唯一标识相应数据库表中的每一行。执行此操作的最直接方式是使用 @PrimaryKey 为单个列添加注解:
Kotlin
@PrimaryKey val id: Int
Java
@PrimaryKey
public int id;
注意:如果您需要 Room 为实体实例分配自动 ID,请将 @PrimaryKey 的 autoGenerate 属性设为 true。
定义复合主键
如果您需要通过多个列的组合对实体实例进行唯一标识,则可以通过列出 @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;
}
如果实体继承了父实体的字段,则使用 @Entity 属性的 ignoredColumns 属性通常会更容易:
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;
}
注意:已启用 FTS 的表始终使用 INTEGER 类型的主键且列名称为 “rowid”。如果是由 FTS 表支持的实体定义主键,则必须使用相应的类型和列名称。
如果表支持以多种语言显示的内容,请使用 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;
}
有时,数据库中的某些字段或字段组必须是唯一的。 您可以通过将 @Index 注解的 unique 属性设为 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 的对象
注意:此功能旨在用于基于 Java 的实体。如需在基于 Kotlin 的实体中实现相同的功能,最好改用数据类。
在 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);
}
}
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2023-05-01。