如何在Android中使用删除表操作处理自动迁移

pnwntuvh  于 2024-01-04  发布在  Android
关注(0)|答案(1)|浏览(203)

我一直在尝试自动迁移,其中一个表将被删除,到我的房间数据库。我指定自动迁移如下:

  1. @Database(
  2. version = 9,
  3. entities = [...],
  4. views = [...],
  5. exportSchema = true,
  6. autoMigrations = [
  7. ...
  8. AutoMigration(8, 9)
  9. ]
  10. )
  11. @TypeConverters(
  12. value = [...],
  13. builtInTypeConverters = BuiltInTypeConverters(enums = BuiltInTypeConverters.State.ENABLED)
  14. )

字符串
当我尝试构建项目时,我得到以下错误:

  1. AutoMigration Failure: Please declare an interface extending 'AutoMigrationSpec',
  2. and annotate with the @RenameTable or @DeleteTable annotation to specify the change
  3. to be performed:
  4. 1) RENAME:
  5. @RenameTable.Entries(
  6. @RenameTable(
  7. fromTableName = "some_table",
  8. toTableName = <NEW_TABLE_NAME>
  9. )
  10. )
  11. 2) DELETE:
  12. @DeleteTable.Entries(
  13. @DeleteTable(
  14. tableName = "some_table"
  15. )
  16. )


我还从实体列表中删除了表类,即SomeTable::class。
在错误之后,我声明一个AutoMigrationSpec类,用@DeleteTable注解,如下所示:

  1. @DeleteTable("some_table")
  2. class Version9 : AutoMigrationSpec


并添加声明它作为规范,如下所示:

  1. @Database(
  2. version = 9,
  3. entities = [...],
  4. views = [...],
  5. exportSchema = true,
  6. autoMigrations = [
  7. ...
  8. AutoMigration(8, 9, Version9::class)
  9. ]
  10. )
  11. @TypeConverters(
  12. value = [...],
  13. builtInTypeConverters = BuiltInTypeConverters(enums = BuiltInTypeConverters.State.ENABLED)
  14. )


我得到了以下相同的错误。
如果我使用规范作为接口而不是类,

  1. @DeleteTable("some_table")
  2. interface Version9 : AutoMigrationSpec


我得到一个额外的错误,The AutoMigration spec type must be a class.
在声明AutoMigrationSpec时,我还尝试使用以下格式:

  1. @DeleteTable.Entries(DeleteTable("some_table"))
  2. class Version9 : AutoMigrationSpec


但是,我得到了最初的错误。

mm5n2pyu

mm5n2pyu1#

我看不出你提供的代码有什么问题。
基于您的代码,假设其他代码,编码使之前和之后运行相对简单,使用KAPT而不是KSP并使用2.5.2 Room库,然后代码按照日志输出的预期工作(参见下面的代码):

第1部分为第一版,有2个表(T1和T2):-

  1. 2024-01-02 11:29:24.237 D/DBINFO1SCHEMA: SQL FOR COMPONENT is
  2. CREATE TABLE android_metadata (locale TEXT)
  3. 2024-01-02 11:29:24.237 D/DBINFO1SCHEMA: SQL FOR COMPONENT is
  4. CREATE TABLE `T1` (`t1Id` INTEGER, `t1Name` TEXT NOT NULL, PRIMARY KEY(`t1Id`))
  5. 2024-01-02 11:29:24.237 D/DBINFO1SCHEMA: SQL FOR COMPONENT is
  6. CREATE TABLE `T2` (`t2Id` INTEGER, `t2Name` TEXT NOT NULL, PRIMARY KEY(`t2Id`))
  7. 2024-01-02 11:29:24.237 D/DBINFO1SCHEMA: SQL FOR COMPONENT is
  8. CREATE TABLE room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)
  9. 2024-01-02 11:29:24.308 D/DBINFO1: logDBInfo function INVOKED and STARTED for DATABASE VERSION 1
  10. 2024-01-02 11:29:24.308 D/DBINFO1T1: T1 ID is 1 NAME is T1Test001_1
  11. 2024-01-02 11:29:24.308 D/DBINFO1T1: T1 ID is 2 NAME is T1Test002_1
  12. 2024-01-02 11:29:24.308 D/DBINFO1T1: T1 ID is 3 NAME is T1Test003_1
  13. 2024-01-02 11:29:24.308 D/DBINFO1T2: T2 ID is 1 NAME is T2Test001
  14. 2024-01-02 11:29:24.309 D/DBINFO1: logDBInfo function INVOKED and STARTED for DATABASE VERSION 1

字符串

第二个版本(迁移)的第2部分,只有一个表(T1):-

  1. 2024-01-02 11:33:47.231 D/DBINFO2SCHEMA: SQL FOR COMPONENT is
  2. CREATE TABLE android_metadata (locale TEXT)
  3. 2024-01-02 11:33:47.231 D/DBINFO2SCHEMA: SQL FOR COMPONENT is
  4. CREATE TABLE `T1` (`t1Id` INTEGER, `t1Name` TEXT NOT NULL, PRIMARY KEY(`t1Id`))
  5. 2024-01-02 11:33:47.231 D/DBINFO2SCHEMA: SQL FOR COMPONENT is
  6. CREATE TABLE room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)
  7. 2024-01-02 11:33:47.237 D/DBINFO2: logDBInfo function INVOKED and STARTED for DATABASE VERSION 2
  8. 2024-01-02 11:33:47.237 D/DBINFO2T1: T1 ID is 1 NAME is T1Test001_1
  9. 2024-01-02 11:33:47.237 D/DBINFO2T1: T1 ID is 2 NAME is T1Test002_1
  10. 2024-01-02 11:33:47.237 D/DBINFO2T1: T1 ID is 3 NAME is T1Test003_1
  11. 2024-01-02 11:33:47.238 D/DBINFO2: logDBInfo function INVOKED and STARTED for DATABASE VERSION 2

  • 即,模式已按预期改变(T2不再存在),沿着还有剩余的数据(仅在DB版本为1时写入)。

完整的代码是:

所有DB代码(根据第2次运行 (参见第1次运行的注解)):-

  1. const val DBVERSION=2;
  2. const val DBFILENAME = "the_dataabse.db"
  3. @Entity
  4. data class T1(
  5. @PrimaryKey
  6. var t1Id: Long?=null,
  7. var t1Name: String
  8. )
  9. @Entity
  10. data class T2(
  11. @PrimaryKey
  12. var t2Id: Long?=null,
  13. var t2Name: String
  14. )
  15. @Dao
  16. interface T1DAOs {
  17. @Insert
  18. fun insert(t1: T1): Long
  19. @Query("SELECT * FROM t1")
  20. fun getAllT1s(): List<T1>
  21. }
  22. @Dao
  23. interface T2DAOs {
  24. @Insert
  25. fun insert(t2: T2): Long
  26. @Query("SELECT * FROM t2")
  27. fun getAllT2s(): List<T2>
  28. }
  29. @Database(entities = [T1::class/*,T2::class COMMENTED OUT FOR V2 */], version = DBVERSION, exportSchema = true
  30. ,autoMigrations = [AutoMigration(1,2,Version1To2::class)]
  31. )
  32. abstract class TheDatabase: RoomDatabase() {
  33. abstract fun getT1DAOs(): T1DAOs
  34. /*abstract fun getT2DAOs(): T2DAOs COMMENTED OUT FOR V2*/
  35. companion object {
  36. private var instance: TheDatabase?=null
  37. fun getInstance(context: Context): TheDatabase {
  38. if (instance==null) {
  39. instance = Room.databaseBuilder(context,TheDatabase::class.java, DBFILENAME)
  40. .allowMainThreadQueries()
  41. .build()
  42. }
  43. return instance as TheDatabase
  44. }
  45. }
  46. }
  47. @DeleteTable(tableName = "T2")
  48. class Version1To2: AutoMigrationSpec

活动代码 (为简洁起见,在主线程上运行,第二次运行时再次运行,再次参考第一版的注解):-

  1. const val TAG = "DBINFO"
  2. class MainActivity : AppCompatActivity() {
  3. lateinit var db: TheDatabase
  4. lateinit var t1DAOs: T1DAOs
  5. lateinit var t2DAOs: T2DAOs
  6. override fun onCreate(savedInstanceState: Bundle?) {
  7. super.onCreate(savedInstanceState)
  8. setContentView(R.layout.activity_main)
  9. db = TheDatabase.getInstance(this)
  10. db.openHelper.writableDatabase /* force database open and thus create/migration etc */
  11. logDBSchema()
  12. t1DAOs = db.getT1DAOs()
  13. if (DBVERSION==1) {
  14. t1DAOs.insert(T1(t1Name ="T1Test001_${DBVERSION}"))
  15. t1DAOs.insert(T1(t1Name = "T1Test002_${DBVERSION}"))
  16. t1DAOs.insert(T1(t1Name = "T1Test003_${DBVERSION}"))
  17. /* COMMENTED OUT FOR V2
  18. t2DAOs = db.getT2DAOs()
  19. t2DAOs.insert(T2(t2Name = "T2Test001"))
  20. logDBInfo(t1DAOs.getAllT1s(),t2DAOs.getAllT2s())
  21. */
  22. } else {
  23. logDBInfo(t1DAOs.getAllT1s())
  24. }
  25. }
  26. fun logDBInfo(rowsFromTable1: List<T1> = listOf(), rowsFromTable2: List<T2> = listOf()) {
  27. Log.d(TAG+ DBVERSION,"logDBInfo function INVOKED and STARTED for DATABASE VERSION ${DBVERSION}")
  28. for (t1 in rowsFromTable1) {
  29. Log.d(TAG+ DBVERSION+"T1","T1 ID is ${t1.t1Id} NAME is ${t1.t1Name}")
  30. }
  31. for (t2 in rowsFromTable2) {
  32. Log.d(TAG+ DBVERSION+"T2","T2 ID is ${t2.t2Id} NAME is ${t2.t2Name}")
  33. }
  34. Log.d(TAG+ DBVERSION,"logDBInfo function INVOKED and STARTED for DATABASE VERSION ${DBVERSION}")
  35. }
  36. fun logDBSchema() {
  37. var cursor: Cursor? = null
  38. if(db != null && db.isOpen) {
  39. cursor=db.openHelper.writableDatabase.query("SELECT sql FROM sqlite_master")
  40. } else {
  41. cursor =SQLiteDatabase.openDatabase(this.getDatabasePath(
  42. DBFILENAME).path,null,0).rawQuery("SELECT sql FROM sqlite_master",null)
  43. }
  44. if (cursor != null) {
  45. while (cursor.moveToNext()) {
  46. Log.d(TAG+ DBVERSION+"SCHEMA","SQL FOR COMPONENT is \n\t${cursor.getString(0)}")
  47. }
  48. }
  49. }
  50. }

结论

基本上,正如最初所说的,代码没有明显的问题。

  • 需要注意的是,使用的是2.5.2房间库,如果这不是您使用的版本,请尝试使用2.5.2
  • 这是不是未知的错误出现,例如,这个Q & A处理库中的一个错误。该链接也有一个修复使用手动迁移。
  • 使用手动迁移可以更好地控制迁移过程
  • 如果使用KSP,然后尝试使用KAPT,则使用KAPT时遇到的问题较少。
展开查看全部

相关问题