【组件篇3】关于Room的使用

198 阅读3分钟

一分耕耘、一分收获,为了使用时忘记,或无处查询,本文记录的是Room的一些使用方法,并持续更新

Room持久性库在SQLite的基础上提供了一个抽象层

1.1 创建Entity(实体类),并指定数据库表

@Entity注解是标识实体类,并通过tableName指定该实体类指向的表名,@PrimaryKey注解标识主键

@Entity Represents a table within the database. Room creates a table for each class that has @Entity annotation, the fields in the class correspond to columns in the table. Therefore, the entity classes tend to be small model classes that don't contain any logic

创建步骤:

  1. 创建实体类
  2. 通过Entity注解标识实体类,通过tableName指定表名
//例1 创建表
@Entity(tableName = "user_table")
class User{
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0
    var firstName: String? = null
    var lastName: String? = null
    var age: Int = 0
}

//例2 创建表
@Entity(
    tableName = "table_pic",
    indices = [Index(
        value = ["imageId"],
        unique = true
    )]
)
class PicEntity : Pic() {
}

1.2 创建Dao接口或抽象类,注解定义数据的增删改查方法

@Dao DAOs are reponsible for defining the methods that access the database. This is the place where we write our queries

创建步骤:

  1. 创建Dao接口或者抽象
  2. 在接口或者抽象类中定义方法,通过注解定义数据的增删改查方法,如下所示
//例1 接口
@Dao
interface UserDao {
    @Query("SELECT * FROM user_table ORDER BY id ASC")
    fun readAllData(): LiveData<List<User>>
}

//例2 抽象类
@Dao
abstract class FestivalDao : DaoProxy() {
}

1.3 创建数据库Database,继承RoomDatabase

@Database Contains the database holder and serves as the main access point for the underlying connection to your app's data

创建步骤:

  1. 创建抽象类Database继承RoomDatabase
  2. 定义抽象方法返回Dao实例
  3. 通过@Database注解标识数据库,通过entities指定有哪些实体类即对应哪些表,version指定版本号
@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class UserDatabase: RoomDatabase() {
    abstract fun userDao(): UserDao

    private class DatabaseCallback : RoomDatabase.Callback() {

        override fun onCreate(db: SupportSQLiteDatabase) {
            PictorialLog.i(TAG, "onCreate")
            super.onCreate(db)
        }

        override fun onOpen(db: SupportSQLiteDatabase) {
            PictorialLog.i(TAG, "onOpen")
            super.onOpen(db)
        }

        override fun onDestructiveMigration(db: SupportSQLiteDatabase) {
            PictorialLog.w(TAG, "onDestructiveMigration")
        }
    }

    companion object {
        private const val TAG = "UserDatabase"

        @JvmStatic
        val instance: UserDatabase by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            val context = BaseApplication.getInstance()
            createDB(context)
        }

        private fun createDB(appContext: Context): UserDatabase {
            val migrations = mutableListOf(
                object : Migration(1, 2) {
                    override fun migrate(database: SupportSQLiteDatabase) {

                    }

                }
            )//迁移后需要修改DATABSASE_VERSION

            val database = Room.databaseBuilder(appContext, UserDatabase::class.java,"user_database")
                .fallbackToDestructiveMigration()//如果数据库版本升级(查不到对应的migration),则丢弃原数据,适用于room初始版本
                .allowMainThreadQueries()
                .addCallback(DatabaseCallback())
                .addMigrations(*migrations.toTypedArray())
                .build()

            return database
        }
    }
}

1.4 增加字段

在class User 中增加字段,如增加city

@Entity(tableName = "user_table")
class User{
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0
    var firstName: String? = null
    var lastName: String? = null
    var age: Int = 0
    var city: String? = null
}

同时记得更新对应的equals、hashCode、update方法

1.5 更改索引约束条件

@Entity(tableName = "user_table", indices = [Index(
        value = [firstName, lastName],
        unique = true
    )])
class User{
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0
    var firstName: String? = null
    var lastName: String? = null
    var age: Int = 0
    var city: String? = null
}

数据库升级更新索引

database.execSQL("DROP INDEX IF EXISTS `index_user_table_firstName`")
database.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_user_table_firstName_lastName` ON `user_table` (`firstName`,`lastName`)")

2 数据库升级

2.1 修改版本号

2.2 增加Migration

val migrations = mutableListOf(
    object : Migration(1, 2) {
        override fun migrate(database: SupportSQLiteDatabase) {
            database.execSQL("ALTER TABLE user_table ADD COLUMN school DEFAULT NULL")
        }

    }
)//迁移后需要修改DATABSASE_VERSION

3 遇到的问题

3.1 更新数据不生效

// 判断数据库中是否已经存在相同日期的数据
val existingEntity = getEntityByDate(entity.date)
if (existingEntity != null) {
	// 如果存在,则更新该数据
	updateEntity(entity)
} else {
	// 如果不存在,则插入一条新数据
	insertEntity(entity)
}

执行上述代码更新数据不生效,原因为entity的id与existingEntity的id不一致,导致更新失败,修复后的代码为:

// 判断数据库中是否已经存在相同日期的数据
val existingEntity = getEntityByDate(entity.date)
if (existingEntity != null) {
	// 如果存在,则将entity的信息赋给existingEntity,然后进行更新
        existingEntity.count = entity.count
	updateEntity(existingEntity)
} else {
	// 如果不存在,则插入一条新数据
	insertEntity(entity)
}

3.2 数据库的查询返回数据一定是可空的