Android Jetpack--Room之Dao详解

       这里只对Dao的使用做详细介绍,Room的具体用法请参看:https://blog.csdn.net/BigBoySunshine/article/details/97763992

1、Insert(添加)

       当你创建DAO方法并添加@Insert注解时,Room会生成一个具体的实现方法,在一个独立的事务中往数据库插入所有的参数。

@Dao
interface MyDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertUsers(vararg users: User)

    @Insert
    fun insertBothUsers(user1: User, user2: User)

    @Insert
    fun insertUsersAndFriends(user: User, friends: List<User>)
}

       如果@Insert方法接收的是一个参数,会有一个long类型的返回值,也就是新插入的数据的rowId。如果传入的参数是一个数组或集合,则返回long[]或List<Long>。

2、Update(更新)

       Update注解的方法可以修改一些传入参数对应的数据库中的实体。 它通过每个实体的主键来进行匹配。

@Dao
interface MyDao {
    @Update
    fun updateUsers(vararg users: User)
}

       你可以让该方法返回一个int值,表示数据库中更新的行数,不过通常没必要这么做。

3、Delete(删除)

       Delete方法可以根据传入的参数,删除数据库中对应的数据。同样也是根据主键来找到要删除的实体对象。

@Dao
interface MyDao {
    @Delete
    fun deleteUsers(vararg users: User)
}

像Update一样,可以返回一个int值,表示数据库中更新的行数。

4、Query for information(查询)

       @Query 是DAO中常用的注解,它可以对数据库执行读写操作。每一个@Query 方法都会在编译阶段进行语法校验,所以如果存在语法错误会在编译阶段报错,而不是在运行时抛出异常。

4.1、Simple queries(简单查询)

       一个简单的查询加载所有的user:

@Dao
interface MyDao {
    @Query("SELECT * FROM user")
    fun loadAllUsers(): Array<User>
}

4.2、Passing parameters into the query(传参数到查询语句)

       大多数时候,需要传参数到查询语句中来执行过滤的操作,比如获取年龄大于18的用户。为了实现这个需求,可以在Room注解中使用方法的参数,如下:

@Dao
interface MyDao {
    @Query("SELECT * FROM user WHERE age > :minAge")
    fun loadAllUsersOlderThan(minAge: Int): Array<User>
}

       在编译阶段,Room通过参数名来匹配:minAge绑定参数和minAge方法参数,如果有错误,会在编译时抛出异常。

同样的,可以传递多个参数或在查询中引用多次,如下:

@Dao
interface MyDao {
    @Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
    fun loadAllUsersBetweenAges(minAge: Int, maxAge: Int): Array<User>

    @Query("SELECT * FROM user WHERE first_name LIKE :search " +
           "OR last_name LIKE :search")
    fun findUserWithName(search: String): List<User>
}

4.3、Returning subsets of columns(返回指定列)

       大多数时候,只需要获取实体的一些列,比如,UI只需要显示用户的姓名和性别,而不需要用户的详细信息。查询指定列可以帮助节约宝贵的资源,并且可以提高查询效率。

       Room允许在查询中对结果列进行映射,进而返回任何基于Java的对象。比如:建立如下POJO(plain old Java-based object)来获取用户的姓和名。

data class NameTuple(
    @ColumnInfo(name = "first_name") val firstName: String?,
    @ColumnInfo(name = "last_name") val lastName: String?
)

       现在就可以在查询中使用这个POJO:

@Dao
interface MyDao {
    @Query("SELECT first_name, last_name FROM user")
    fun loadFullName(): List<NameTuple>
}

       Room查询并返回first_name 和last_name,并将他们映射成NameTuple类的列。如果查询返回太多的列,或某个列在NameTuple类中不存在,Room提示警告。

4.4、Passing a collection of arguments(查询中传入集合参数)

       有时候查询需要传入一些参数,同时一些参数在运行时才能确定。比如:需要从一个用户集合中查找满足一些条件的用户。

@Dao
interface MyDao {
    @Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
    fun loadUsersFromRegions(regions: List<String>): List<NameTuple>
}

4.5、Observable queries(可观察的查询)

       在进行查询时,可能需要当数据更新时app的UI自动更新。LiveData可以实现这一功能。

@Dao
interface MyDao {
    @Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
    fun loadUsersFromRegionsSync(regions: List<String>): LiveData<List<User>>
}

4.6、Reactive queries with RxJava(查询结果使用RxJava)

Room提供了如下支持来返回RxJava2类型的值

       要使用这些返回类型,需要在app/build.gradle中添加如下依赖:

dependencies {
    def room_version = "2.1.0"
    implementation 'androidx.room:room-rxjava2:$room_version'
}

       使用方法如下:

@Dao
interface MyDao {
    @Query("SELECT * from user where id = :id LIMIT 1")
    fun loadUserById(id: Int): Flowable<User>

    // Emits the number of users added to the database.
    @Insert
    fun insertLargeNumberOfUsers(users: List<User>): Maybe<Int>

    // Makes sure that the operation finishes successfully.
    @Insert
    fun insertLargeNumberOfUsers(varargs users: User): Completable

    /* Emits the number of users removed from the database. Always emits at
       least one user. */
    @Delete
    fun deleteAllUsers(users: List<User>): Single<Int>
}

4.7、Direct cursor access(直接返回cursor)

       如果app的逻辑需要直接使用返回的rows,可以在查询中返回一个Cursor对象,如下一小段代码:

@Dao
interface MyDao {
    @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")
    fun loadRawUsersOlderThan(minAge: Int): Cursor
}

Caution: It's highly discouraged to work with the Cursor API because it doesn't guarantee whether the rows exist or what values the rows contain. Use this functionality only if you already have code that expects a cursor and that you can't refactor easily.

4.8、Querying multiple tables(多表查询)

       一些查询可能需要进行多表查询,Room支持各种查询方式,因此可以进行连接查询。如果返回结果是一个观察数据类型,比如:Flowable或LiveData,Room观察所有查询中的关联表来更新数据。

       如下代码展示了怎么执行一个表连接,来将包含借书用户的表和包含借出书信息的表进行合并:

@Dao
interface MyDao {
    @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>
}

       这里也可以用POJOs来获取指定的列信息:

@Dao
interface MyDao {
    @Query(
        "SELECT user.name AS userName, pet.name AS petName " +
        "FROM user, pet " +
        "WHERE user.id = pet.user_id"
    )
    fun loadUserAndPetNames(): LiveData<List<UserPet>>

    // You can also define this class in a separate file.
    data class UserPet(val userName: String?, val petName: String?)
}

4.9、Write async methods with Kotlin coroutines(利用Kt协成写异步方法)

       可以利用Kotlin的协成功能在Dao方法上添加suspend 关键字来实现异步操作。这里需要确保不能在主线程中执行他们。

@Dao
interface MyDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertUsers(vararg users: User)

    @Update
    suspend fun updateUsers(vararg users: User)

    @Delete
    suspend fun deleteUsers(vararg users: User)

    @Query("SELECT * FROM user")
    suspend fun loadAllUsers(): Array<User>
}

       Dao的方法可以使用 @Transaction注解,利用这一特性来创建suspending数据库方法,这种方法会运行在独立的数据库事务中。

@Dao
abstract class UsersDao {
    @Transaction
    open suspend fun setLoggedInUser(loggedInUser: User) {
        deleteUser(loggedInUser)
        insertUser(loggedInUser)
    }

    @Query("DELETE FROM users")
    abstract fun deleteUser(user: User)

    @Insert
    abstract suspend fun insertUser(user: User)
}

参考:https://developer.android.com/training/data-storage/room/accessing-data.html#kotlin

发布了71 篇原创文章 · 获赞 53 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/BigBoySunshine/article/details/97765514