使用Room持久性库时,可以将相关字段集定义为实体。 对于每个实体,在关联的Database对象中创建一个表来保存项目。
默认情况下,Room会为实体中定义的每个字段创建一列。 如果实体具有您不想保留的字段,则可以使用@Ignore
对其进行注释。 您必须通过Database类中的entities数组引用实体类。
以下代码段显示了如何定义实体:
@Entity
public class User {
@PrimaryKey
public int id;
public String firstName;
public String lastName;
@Ignore
Bitmap picture;
}
为了持久一个参数,Room必须能够访问它。 您可以将字段设为公开,也可以为其提供getter和setter。 如果使用getter和setter方法,请记住它们基于Room中的JavaBeans约定。
注意:实体可以有一个空构造函数(如果相应的DAO类可以访问每个持久化字段),或者一个构造函数,其参数包含与实体中字段匹配的类型和名称。 Room也可以使用完整或部分构造函数,例如只接收某些字段的构造函数。
一、使用主键
每个实体必须至少定义一个字段作为主键。 即使只有一个字段,您仍然需要使用@PrimaryKey
注释来注释该字段。 此外,如果您希望Room为实体分配自动ID,您可以设置@PrimaryKey
的autoGenerate属性。 如果实体具有复合主键,则可以使用@Entity
批注的primaryKeys属性,如以下代码段所示:
@Entity(primaryKeys = {"firstName", "lastName"})
public class User {
public String firstName;
public String lastName;
@Ignore
Bitmap picture;
}
默认情况下,Room使用类名作为数据库表名。 如果希望表具有不同的名称,请设置@Entity
批注的tableName属性,如以下代码段所示:
@Entity(tableName = "users")
public class User {
...
}
警告:SQLite中的表名称不区分大小写。
与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
Bitmap picture;
}
二、注释索引和唯一性
根据您访问数据的方式,您可能希望索引数据库中的某些字段以加快查询速度。 要向实体添加索引,请在@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;
}
三、定义对象之间的关系
由于SQLite是关系数据库,因此您可以指定对象之间的关系。 尽管大多数对象关系映射库允许实体对象相互引用,但Room明确禁止这样做。 要了解此决策背后的技术推理,请参阅了解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操作。 这种替换冲突值的方法可能会影响您的外键约束。
四、创建嵌套对象
有时,您希望将实体或普通旧Java对象(POJO)表达为数据库逻辑中的一个整体,即使该对象包含多个字段。 在这些情况下,您可以使用@Embedded批注来表示要分解到表中子字段的对象。 然后,您可以像查找其他单个列一样查询嵌入字段。
例如,我们的User类可以包含Address类型的字段,它表示名为street,city,state和postCode的字段的组合。 要将组合列分别存储在表中,请在User类中包含使用@Embedded
注释的Address字段,如以下代码段所示:
public class Address {
public String street;
public String state;
public String city;
@ColumnInfo(name = "post_code")
public int postCode;
}
@Entity
public class User {
@PrimaryKey
public int id;
public String firstName;
@Embedded
public Address address;
}
然后,表示User对象的表包含具有以下名称的列:id,firstName,street,state,city和post_code。
注意:嵌入字段还可以包含其他嵌入字段。
如果实体具有多个相同类型的嵌入字段,则可以通过设置prefix属性使每个列保持唯一。 然后,Room将提供的值添加到嵌入对象中每个列名称的开头。
网友评论