将存储用户数据的房间数据库迁移到具有预填充数据的新表的数据库

问题描述 投票:0回答:1

我有一个位于资产文件夹中的数据库。它包含预先填充的表以及存储用户输入数据的表。现在,我们已经完成了应用程序的另一部分,并计划解锁这部分。问题是数据库现在包含带有预填充值的新表。

如何将现有数据库迁移到新数据库,确保维护用户输入的数据和新的预填充表值?

我有以下代码,它正确地将新表添加到现有数据库,但它不保留预先填充的数据。我知道我可以使用插入语句来添加预先填充的数据,但这需要数百条语句。

val migration1to2 = object: Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
            database.execSQL("CREATE TABLE IF NOT EXISTS 'users' ('id' INTEGER NOT NULL UNIQUE, 'name' TEXT NOT NULL, 'specid' TEXT NOT NULL, PRIMARY KEY('id' AUTOINCREMENT))")
    }
}

Room.databaseBuilder(context, InspectionDatabase::class.java, "inspection_db.db")
    .createFromAsset("inspection.db")
    .setJournalMode(JournalMode.TRUNCATE)
    .allowMainThreadQueries()
    .addMigrations(InspectionDatabase.migration1to2)
    .build()
android kotlin android-studio migration android-room
1个回答
0
投票

我知道我可以使用插入语句来添加预先填充的数据,但这需要数百条语句。

在迁移中您可以:-

  1. 复制资产数据库。
  2. 将复制的资产数据库 (inspeciton.db) 作为 SQLiteDatabase 打开。
  3. 将复制的资产数据库中的数据提取到游标中
  4. 根据提取的数据遍历光标插入行
  5. 关闭光标
  6. 删除复制的资产数据库

大致如下:-

companion object {
    private var instance: InspectionDatabase?=null
    private lateinit var currentContext: Context
    fun getInstance(context: Context): InspectionDatabase {
        currentContext=context
        if ( instance==null) {
            instance = Room.databaseBuilder(context,InspectionDatabase::class.java,"inspection_db.db")
                .allowMainThreadQueries()
                .createFromAsset("inspection.db")
                .addMigrations(migration1to2)
                .build()
        }
        return instance as InspectionDatabase
    }
    val migration1to2 = object: Migration(1, 2) {
        override fun migrate(database: SupportSQLiteDatabase) {
            val assetDBPath = currentContext!!.getDatabasePath("inspection.db").path
            val assetInputStream = currentContext!!.assets.open("inspection.db")
            val assetDBSCHEMA = "ads"
            assetInputStream.copyTo(FileOutputStream(assetDBPath))
            assetInputStream.close()
            database.execSQL("CREATE TABLE IF NOT EXISTS `users` ('id' INTEGER NOT NULL UNIQUE, 'name' TEXT NOT NULL, 'specid' TEXT NOT NULL, PRIMARY KEY('id' AUTOINCREMENT))")
            /*

            database.execSQL("ATTACH DATABASE $assetDBPath AS $assetDBSCHEMA")
            database.execSQL("INSERT INTO `users` SELECT * FROM ${assetDBSCHEMA}.users")
            database.execSQL("DETACH DATABASE $assetDBSCHEMA")
             */
            val assetDB = SQLiteDatabase.openDatabase(assetDBPath,null,0)
            val cv = ContentValues()
            val csr = assetDB.query("users",null,null,null,null,null,null)
            val idIx = csr.getColumnIndex("users")
            val nameIx = csr.getColumnIndex("name")
            val specidIx = csr.getColumnIndex("specid")
            while (csr.moveToNext()) {
                cv.clear()
                cv.put("users",csr.getLong(idIx))
                cv.put("name",csr.getString(nameIx))
                cv.put("specid",csr.getString(specidIx))
                database.insert("users",OnConflictStrategy.IGNORE,cv)
            }
            csr.close()
            if (File(assetDBPath).exists()) File(assetDBPath).delete()
        }
    }
  • 请注意,注释掉的 ATTACH 不能使用,因为迁移是在事务内进行的(可以看出,附加复制的资产数据库会更简单)。

  • 为了简洁起见,代码是使用主线程进行测试的。

注意到以这种方式获取上下文并不理想,也许可以 在 kotlin 中的伴随对象中访问应用程序上下文

© www.soinside.com 2019 - 2024. All rights reserved.