说明:
Android Room 第二篇 - Entity使用
主要介绍entity的作用
原文地址:https://developer.android.com/training/data-storage/room/defining-data
第一篇:Android Room概述
使用Room entities 来定义数据
当你在使用Room的时候,定义了一组相关的字段作为一个实体。对于每个实体,都会通过在数据库里面创建一张表的方式来处理这些数据。
通常来说,Room 会为实体类中定义的每个字段在数据库中创建“列”。如果实体类中有某个字段你不想在数据库中进行存储的,你可以对这些字段使用@Ignore注解。
下面这个代码块展示了如何定义一个实体
@Entity
public class User {
@PrimaryKey
public int id;
public String firstName;
public String lastName;
@Ignore
Bitmap picture;
}
为了能够保存某个字段,Room必须能够对它进行操作。你可以使用public修饰符,或者你可以提供getter和setter方法。如果你选择后者,记住Room是基于JavaBeans约定的。
主键
每个实体必须定义至少一个字段作为主键。即使是实体只有一个字段,你仍然需要对该字段使用@PrimaryKey注解。同时,如果你想通过Room来自动分配ID,也可以设置@PrimaryKey的autoGenerate属性。如果实体有组合主键,你可以通过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是明确禁止的。如果你想知道这个决定背后的技术原因,可以参见:Understand why Room doesn’t allow object references.
虽然你不能使用直接关系,Room仍然允许你在实体之间定义外键。
例如,如果有另一个实体叫做Book,你可以在User实体下使用@ForeignKey注解来定义他们之间的关系,就像下面的代码段所示:
@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删除这个User下所有的books
注意: SQLite 处理 @Insert(onConflict = REPLACE) 的时候看作是 REMOVE 和 REPLACE 操作,而不是单纯的UPDATE操作。这个方法会替换冲突值,同时也会对外键约束有影响。更多细节请看:SQLite documentation
创建嵌套对象
有时,你希望将实体或普通旧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将提供的值添加到嵌入对象中每个列名称的开头。