在 Room 数据库中创建视图

一、前言

    视图是一个或者多个基本表(视图)构建的一个虚拟表,使用视图有许多的好处,其中主要的两个好处是封装查询和灵活的安全性控制。Room 从2.1.0 及更高版本开始支持 SQLite 数据库视图功能,你可以将查询封装到一个类中, Room 将这些支持查询的类称之为视图,视图在 DAO 中使用跟普通的数据实体对象一样。更多关于视图的相关内容大家可以自行学习,在本篇幅,我们将详细介绍在 Room 中创建视图并使用。

注意事项:跟数据实体类一样,你可以在视图中执行 SELECT 查询语句,但是你无法在视图中执行 INSERTUPDATEDELETE 语句。换句话说,视图只有读权限,没有写权限,这就是安全性控制的一个特点。

二、 在Room中使用视图

2.1 创建视图类

    Room 创建视图非常简单,定义一个数据类(跟数据实体类一样,不过对应的是视图,不是实体表),使用 @DatabaseView 注解进行标注,@DatabaseView 有两个参数,一个是 viewName (自定义视图名称,可选),另一个是 values(视图数据对应的 SQL 查询语句)。如下示例所示:

// 数据实体类(实体表),视图类对应数据实体类(实体表)
@Entity(tableName = "schools")
data class School(@PrimaryKey val sid: Int, val name: String, val addr: String)

@Entity(tableName = "students")
data class Student(@PrimaryKey val sid: Int, val name: String, val age: Int, val schoolId: Int, val addr: String?)

// 创建视图类,@DatabaseView 注解可以用 viewName 参数指定视图名称,如果不指定视图名称,@DatabaseView 注解默认参数是 value
//@DatabaseView(viewName = "student_school", value = "SELECT students.sid, students.name, students.age, " +
//        "schools.sid AS schoolId, schools.name AS schoolName " +
//        "FROM students INNER JOIN schools ON students.schoolId = schools.sid")
@DatabaseView("SELECT students.sid, students.name, students.age, " +
        "schools.sid AS schoolId, schools.name AS schoolName " +
        "FROM students INNER JOIN schools ON students.schoolId = schools.sid")
data class StudentWithSchool(
    val sid: Int, 
    val name: String, 
    val age: Int, 
    val schoolId: Int, 
    val schoolName: String)

2.2 在数据库类中声明视图

    创建了视图类之后,需要在数据库定义时声明视图类。在 @Database 注解中的 views 参数进行声明,如下示例所示:

@Database(
entities = [User::class, School::class, Student::class, Profile::class], 
views = [StudentWithSchool::class], 
version = 1)
abstract class AppDatabase: RoomDatabase() {
    abstract fun studentDao(): StudentDao
}

2.3 查询视图获取数据

    在 DAO 类中添加查询视图方法,即可从视图中查询数据。

@Dao
interface StudentDao {
    @Insert
    fun insertAll(vararg student: Student)

    @Insert
    fun insertSchool(vararg schools: School)

    // 查询视图表
    @Query("SELECT * from StudentWithSchool")
    suspend fun getStudentWithSchool() : List<StudentWithSchool>

}

注意事项:视图表只能执行 SELECT 查询操作,不能执行 INSERTUPDATEDELETE 操作。

2.4 数据库迁移时视图的处理

    视图是一个虚拟表,所以在数据库升级迁移时,视图发生变更(新增、删除、修改等)时,也需要进行处理。数据库迁移相关可请参考文章:Android Room 数据库详解。下面通过示例介绍下数据库迁移时视图的处理。

  • 数据库迁移前
// 定义数据库
@Database(entities = [User::class, School::class, Student::class, Profile::class], version = 1)
abstract class AppDatabase: RoomDatabase() {
    abstract fun studentDao(): StudentDao
}

// 构建数据库类
val db = Room.databaseBuilder(applicationContext, AppDatabase::class.java, "app.db")
    .build()
  • 数据库迁移后(新增视图)
// 定义数据库
@Database(entities = [User::class, School::class, Student::class, Profile::class], views = [StudentWithSchool::class], version = 2)
abstract class AppDatabase: RoomDatabase() {
    abstract fun studentDao(): StudentDao
}

// 定义数据库迁移配置
val migration_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        // 这里新建一个视图(视图名称要用两个半角的间隔号括起来)
        database.execSQL("CREATE VIEW `StudentWithSchool` AS SELECT students.sid, students.name, students.age, schools.sid AS schoolId, schools.name AS schoolName FROM students INNER JOIN schools ON students.schoolId = schools.sid")
    }
}

// 构建数据库类
val db = Room.databaseBuilder(applicationContext, AppDatabase::class.java, "app.db")
    .addMigrations(migration_1_2) // 添加数据迁移配置
    .build()

示例讲解:上面的示例中,数据库迁移过程中新增一个视图,在迁移配置中必须手动创建一个视图。跟数据表一样,在 @Database 中声明的视图类,只会在第一次安装创建数据库时才会创建视图,后续添加的必须进行数据库迁移操作。创建视图使用 CREATE VIEW 语法(更多 SQL 语法大家自行学习),不过笔者发现一个很有趣的现象,SQL 语句创建视图时,视图名称直接用字符窜表示即可,但是在 Room 的数据库迁移配置中,必须使用两个半角的间隔号(就是键盘上方 1 数字键左边的那个按键,并不是单引号,这个需要特别注意)。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值