我有一个位于资产文件夹中的数据库。它包含预先填充的表以及存储用户输入数据的表。现在,我们已经完成了应用程序的另一部分,并计划解锁这部分。问题是数据库现在包含带有预填充值的新表。
如何将现有数据库迁移到新数据库,确保维护用户输入的数据和新的预填充表值?
我有以下代码,它正确地将新表添加到现有数据库,但它不保留预先填充的数据。我知道我可以使用插入语句来添加预先填充的数据,但这需要数百条语句。
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()
我知道我可以使用插入语句来添加预先填充的数据,但这需要数百条语句。
在迁移中您可以:-
大致如下:-
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 中的伴随对象中访问应用程序上下文