引言
当您使用 Room 持久性库存储应用的数据时,您可以通过定义数据访问对象 (DAO) 与存储的数据进行交互。每个 DAO 都包含一些方法,这些方法提供对应用数据库的抽象访问权限。在编译时,Room 会自动为您定义的 DAO 生成实现
DAO 剖析
您可以将每个 DAO 定义为一个接口或一个抽象类。
对于基本用例,您通常应使用接口。无论是哪种情况,您都必须始终使用 @Dao
为您的 DAO 添加注解。
DAO 不具有属性,但它们定义了一个或多个方法,可用于与应用数据库中的数据进行交互。
以下代码是一个简单 DAO 的示例,它定义了在 Room 数据库中插入、删除和选择 User
对象的方法:
@Dao
interface UserDao {
@Insert
fun insertAll(vararg users: User)
@Delete
fun delete(user: User)
@Query("SELECT * FROM user")
fun getAll(): List<User>
}
有两种类型的 DAO 方法可以定义数据库交互:
- (便捷方法)可让您在不编写任何 SQL 代码的情况下插入、更新和删除数据库中行的便捷方法。
- (传统SQL语句方法)可让您编写自己的 SQL 查询以与数据库进行交互的查询方法。
便捷方法
Room 提供了方便的注解,用于定义无需编写 SQL 语句即可执行简单插入、更新和删除的方法
- 插入
借助
@Insert
注释,您可以定义将其参数插入到数据库中的相应表中的方法。
@Insert
方法的每个参数必须是带有@Entity
注解的 Room 数据实体类的实例或数据实体类实例的集合。调用@Insert
方法时,Room 会将每个传递的实体实例插入到相应的数据库表中。
如果@Insert
方法接收单个参数,则会返回long
值,这是插入项的新rowId
。如果参数是数组或集合,则该方法应改为返回由long
值组成的数组或集合,并且每个值都作为其中一个插入项的rowId
以下代码展示了将一个或多个User
对象插入数据库的有效@Insert
方法示例:
@Dao
interface UserDao {
//OnConflictStrategy.REPLACE:如果有老的数据存在则会进行替换,如果没有就插入
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertUsers(vararg users: User)
@Insert
fun insertBothUsers(user1: User, user2: User)
@Insert
fun insertUsersAndFriends(user: User, friends: List<User>)
}
- 更新
借助
@Update
注释,您可以定义更新数据库表中特定行的方法。与@Insert
方法类似,@Update
方法接受数据实体实例作为参数。 以下代码展示了一个@Update
方法示例,该方法尝试更新数据库中的一个或多个User
对象(匹配主键更新),@Update
方法可以选择性地返回 int 值,该值指示成功更新的行数
@Dao
interface UserDao {
@Update
fun updateUsers(vararg users: User)
}
- 删除
借助
@Delete
注释,您可以定义从数据库表中删除特定行的方法。与@Insert
方法类似,@Delete
方法接受数据实体实例作为参数。 以下代码展示了一个@Delete
方法示例,尝试从数据库中删除一个或多个User
对象(匹配主键删除),@Delete
方法可以选择性地返回 int 值,该值指示成功删除的行数
@Dao
interface UserDao {
@Delete
fun deleteUsers(vararg users: User)
}
传统SQL语句方法
使用
@Query
注解,您可以编写 SQL 语句并将其作为 DAO 方法公开。使用这些查询方法从应用的数据库查询数据,或者需要执行更复杂的插入、更新和删除操作。
Room 会在编译时验证 SQL 查询。这意味着,如果查询出现问题,则会出现编译错误,而不是运行时失败
- 查询,查询表中所有数据
@Query("SELECT * FROM user")
fun loadAllUsers(): Array<User>
- 查询,返回表格列的子集(另外创建一个新类,只查询数据中的姓名数据,不查询其他数据,节省资源)
在大多数情况下,您只需要返回要查询的表中的列的子集。例如,您的界面可能仅显示用户的名字和姓氏,而不是该用户的每一条详细信息。为节省资源并简化查询的执行,您应只查询所需的字段。
借助 Room,您可以从任何查询返回简单对象,前提是您可以将一组结果列映射到返回的对象。例如,您可以定义以下对象来保存用户的名字和姓氏:
data class NameTuple(
@ColumnInfo(name = "first_name") val firstName: String?,
@ColumnInfo(name = "last_name") val lastName: String?
)
@Query("SELECT first_name, last_name FROM user")
fun loadFullName(): List<NameTuple>
- 查询,将简单参数传递给查询
年龄区间查询
@Query("SELECT * FROM user WHERE age > :minAge")
fun loadAllUsersOlderThan(minAge: Int): Array<User>
@Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
fun loadAllUsersBetweenAges(minAge: Int, maxAge: Int): Array<User>
- 查询,将一组参数传递给查询
@Query("SELECT * FROM user WHERE region IN (:regions)")
fun loadUsersFromRegions(regions: List<String>): List<User>
- 查询,多表联合查询
@Query(
"SELECT * FROM book " +
"INNER JOIN loan ON loan.book_id = book.id " +
"INNER JOIN user ON user.id = loan.user_id " +
"WHERE user.name LIKE :userName"
)
fun findBooksBorrowedByNameSync(userName: String): List<Book>
网友评论