簡體   English   中英

重命名列失敗的房間自動遷移(NOT NULL 約束失敗,生成錯誤的遷移類)

[英]Room auto-migration with rename columns failing (NOT NULL constraint failed, bad generated Migration class)

我最近重命名了 Room 實體中的列,方法是在列上添加前綴setting_

變化的差異

在其他一些變化中,這是它產生的自動遷移 impl:

class AppDatabase_AutoMigration_15_16_Impl extends Migration {
private final AutoMigrationSpec callback = new SettingsRenamedColumnsAutoMigration();

public AppDatabase_AutoMigration_15_16_Impl() {
    super(15, 16);
}

public void migrate(@NonNull SupportSQLiteDatabase database) {
    database.execSQL("ALTER TABLE `merchants` ADD COLUMN `accessLevel` INTEGER NOT NULL DEFAULT 0");
    database.execSQL("CREATE TABLE IF NOT EXISTS `merchantSettings` (`setting_id` INTEGER NOT NULL, `setting_group_id` INTEGER, `setting_type` TEXT NOT NULL, `setting_name` TEXT NOT NULL, `setting_value` TEXT NOT NULL, `setting_data_type` TEXT NOT NULL, `setting_created_at` INTEGER NOT NULL, `setting_updated_at` INTEGER NOT NULL, PRIMARY KEY(`setting_id`), FOREIGN KEY(`setting_group_id`) REFERENCES `merchants`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )");
    database.execSQL("CREATE INDEX IF NOT EXISTS `index_merchantSettings_setting_group_id` ON `merchantSettings` (`setting_group_id`)");
    database.execSQL("CREATE TABLE IF NOT EXISTS `_new_branchSettings` (`setting_id` INTEGER NOT NULL, `setting_branch_id` INTEGER, `setting_type` TEXT NOT NULL, `setting_name` TEXT NOT NULL, `setting_value` TEXT NOT NULL, `setting_data_type` TEXT NOT NULL, `setting_created_at` INTEGER NOT NULL, `setting_updated_at` INTEGER NOT NULL, PRIMARY KEY(`setting_id`), FOREIGN KEY(`setting_branch_id`) REFERENCES `branches`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )");
    database.execSQL("INSERT INTO `_new_branchSettings` (`setting_type`,`setting_updated_at`) SELECT `setting_type`,`updated_at` FROM `branchSettings`");
    database.execSQL("DROP TABLE `branchSettings`");
    database.execSQL("ALTER TABLE `_new_branchSettings` RENAME TO `branchSettings`");
    database.execSQL("CREATE INDEX IF NOT EXISTS `index_branchSettings_setting_branch_id` ON `branchSettings` (`setting_branch_id`)");
    DBUtil.foreignKeyCheck(database, "branchSettings");
    database.execSQL("CREATE TABLE IF NOT EXISTS `_new_branches` (`id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT, `lat` TEXT, `lng` TEXT, `is_default` INTEGER, `email` TEXT, `phone` TEXT, `clover_category_id` TEXT, `clover_gift_item` TEXT, `clover_cashless_item` TEXT, `prep_time` INTEGER, `opening_hours` TEXT, `currency_code` TEXT, `created_at` INTEGER NOT NULL, `updated_at` INTEGER NOT NULL, PRIMARY KEY(`id`))");
    database.execSQL("INSERT INTO `_new_` (`id`,`name`,`address`,`lat`,`lng`,`is_default`,`email`,`phone`,`prep_time`,`opening_hours`,`currency_code`,`created_at`,`updated_at`) SELECT `id`,`name`,`address`,`lat`,`lng`,`is_default`,`email`,`phone`,`prep_time`,`opening_hours`,`currency_code`,`created_at`,`updated_at` FROM `branches`");
    database.execSQL("DROP TABLE `branches`");
    database.execSQL("ALTER TABLE `_new_` RENAME TO `branches`");
    this.callback.onPostMigrate(database);
}

}

使用以下自動遷移規范:

AutoMigration(
        from = 15,
        to = 16,
        spec = AppDatabase.SettingsRenamedColumnsAutoMigration::class
    )


    @RenameColumn.Entries(
    RenameColumn(
        tableName = "branchSettings",
        fromColumnName = "id",
        toColumnName = "setting_id"
    ),
    RenameColumn(
        tableName = "branchSettings",
        fromColumnName = "branch_id",
        toColumnName = "setting_branch_id"
    ),
    RenameColumn(
        tableName = "branchSettings",
        fromColumnName = "name",
        toColumnName = "setting_name"
    ),
    RenameColumn(
        tableName = "branchSettings",
        fromColumnName = "value",
        toColumnName = "setting_value"
    ),
    RenameColumn(
        tableName = "branchSettings",
        fromColumnName = "data_type",
        toColumnName = "setting_data_type"
    ),
    RenameColumn(
        tableName = "branchSettings",
        fromColumnName = "created_at",
        toColumnName = "setting_created_at"
    ),
    RenameColumn(
        tableName = "branchSettings",
        fromColumnName = "updated_at",
        toColumnName = "setting_updated_at"
    ),
)
@DeleteColumn.Entries(
    DeleteColumn(tableName = "branches", columnName = "checkout_category_id")
)
class SettingsRenamedColumnsAutoMigration : AutoMigrationSpec

這個錯誤正在影響我認為的每個更新程序:

android.database.sqlite.SQLiteConstraintException: NOT NULL constraint failed: _new_branchSettings.setting_name (code 1299 SQLITE_CONSTRAINT_NOTNULL)
    at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
    at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:831)
    at android.database.sqlite.SQLiteSession.executeForChangedRowCount(SQLiteSession.java:756)
    at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:66)
    at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1806)
    at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1733)
    at androidx.sqlite.db.framework.FrameworkSQLiteDatabase.execSQL(FrameworkSQLiteDatabase.java:255)
    at loylap.core.sdk.data.local.db.AppDatabase_AutoMigration_15_16_Impl.migrate(AppDatabase_AutoMigration_15_16_Impl.java:31)
    at androidx.room.RoomOpenHelper.onUpgrade(RoomOpenHelper.kt:91)

我不知道足夠多的 MySQL/Room 來確認,但看起來 15->16 遷移 class 至少有 2 個問題。 它創建一個_new_branchSettings表,但只插入 2 個隨機列( setting_typesetting_updated_at )。 它不應該在這里插入所有東西嗎? 因此錯誤 - setting_name應該不是 null。

另外,我很懷疑INSERT INTO ``_new_`` ... _new_是什么,誰創造了它? 對我來說,這看起來像是一個錯字,應該插入到_new_branches中。

這似乎是一個可能的錯誤。 您可能希望將此報告為錯誤。

正如您所建議的,INSERT INTO 似乎正在省略列,因此由於列被省略,這些值將是 null。

我已經查看了INSERT INTO ``_new_``並且(沒有非常仔細地檢查)似乎很好,盡管不是最好的命名約定(可能是一個錯誤,但只有 1 它可能不會導致問題)。

就個人而言,也許比你自己更可疑,我的解決方案是手動遷移,這將更改新分支設置表的 INSERT INTO 以在找到空值時插入默認值(只需通過從所有列中提取和分配值來進行更正就足夠了)。

  • 我遇到過以前的遷移問題,並建議對 go 進行更改,因為這些更改沒有經過很好的測試。

作為手動遷移而不是自動遷移的解決方案將使用(注意未經測試,因此它是*原則代碼):-

  database.execSQL("ALTER TABLE `merchants` ADD COLUMN `accessLevel` INTEGER NOT NULL DEFAULT 0");
  database.execSQL("CREATE TABLE IF NOT EXISTS `merchantSettings` (`setting_id` INTEGER NOT NULL, `setting_group_id` INTEGER, `setting_type` TEXT NOT NULL, `setting_name` TEXT NOT NULL, `setting_value` TEXT NOT NULL, `setting_data_type` TEXT NOT NULL, `setting_created_at` INTEGER NOT NULL, `setting_updated_at` INTEGER NOT NULL, PRIMARY KEY(`setting_id`), FOREIGN KEY(`setting_group_id`) REFERENCES `merchants`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )");
  database.execSQL("CREATE INDEX IF NOT EXISTS `index_merchantSettings_setting_group_id` ON `merchantSettings` (`setting_group_id`)");
  
  /* SPLIT to make the code more readable */
  database.execSQL(
          "CREATE TABLE IF NOT EXISTS `_new_branchSettings` " +
                  "(`setting_id` INTEGER NOT NULL, " +
                  "`setting_branch_id` INTEGER, " +
                  "`setting_type` TEXT NOT NULL, " +
                  "`setting_name` TEXT NOT NULL, " +
                  "`setting_value` TEXT NOT NULL, " +
                  "`setting_data_type` TEXT NOT NULL, " +
                  "`setting_created_at` INTEGER NOT NULL, " +
                  "`setting_updated_at` INTEGER NOT NULL, " +
                  "PRIMARY KEY(`setting_id`), " +
                  "FOREIGN KEY(`setting_branch_id`) REFERENCES `branches`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE " +
                  ")"
  );
  /* SPLIT to make the code more readable */
  database.execSQL("INSERT INTO `_new_branchSettings` (" +
          "`setting_id`," +
          "`setting_branch_id`," +
          "`setting_type`," +
          "`setting_name`," +
          "`setting_value`," +
          "`setting_data_type`," +
          "`setting_created_at`," +
          "`setting_updated_at`" +
          ") " +
          "SELECT " +
          "`id`," +
          "`branch_id`," +
          "coalesce(`settng_type`,'SETTING_TYPEWASNULL')," +
          "coalesce(`name`,'NAMEWASNULL')," +
          "coalesce(`value`,'VALUEWASNULL')," +
          "coalesce(`data_type`,'DATA_TYPEWASNULL')," +
          "coalesce(`created_at`,-9999)," +
          "coalsce(`updated_at`,-8888) " +
          "FROM `branchSettings`" +
          "");
  /* Above INSERT replaces the following suspicious INSERT INTO */
  //database.execSQL("INSERT INTO `_new_branchSettings` (`setting_type`,`setting_updated_at`) SELECT `setting_type`,`updated_at` FROM `branchSettings`");
  database.execSQL("DROP TABLE `branchSettings`");
  database.execSQL("ALTER TABLE `_new_branchSettings` RENAME TO `branchSettings`");
  database.execSQL("CREATE INDEX IF NOT EXISTS `index_branchSettings_setting_branch_id` ON `branchSettings` (`setting_branch_id`)");
  DBUtil.foreignKeyCheck(database, "branchSettings");

  database.execSQL("CREATE TABLE IF NOT EXISTS `_new_branches` (`id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT, `lat` TEXT, `lng` TEXT, `is_default` INTEGER, `email` TEXT, `phone` TEXT, `clover_category_id` TEXT, `clover_gift_item` TEXT, `clover_cashless_item` TEXT, `prep_time` INTEGER, `opening_hours` TEXT, `currency_code` TEXT, `created_at` INTEGER NOT NULL, `updated_at` INTEGER NOT NULL, PRIMARY KEY(`id`))");


  database.execSQL("INSERT INTO `_new_` (`id`,`name`,`address`,`lat`,`lng`,`is_default`,`email`,`phone`,`prep_time`,`opening_hours`,`currency_code`,`created_at`,`updated_at`) SELECT `id`,`name`,`address`,`lat`,`lng`,`is_default`,`email`,`phone`,`prep_time`,`opening_hours`,`currency_code`,`created_at`,`updated_at` FROM `branches`");


  database.execSQL("DROP TABLE `branches`");
  database.execSQL("ALTER TABLE `_new_` RENAME TO `branches`");
  //this.callback.onPostMigrate(database); /* I believe not needed in actual code as generated code should do this as needed */
  • 您可能希望將????WASNULL-9999-8888為更可接受的值,並且可能包括以下 UPADTE 來更改/計算值。
    • 盡管可能永遠不會使用替代品。

    • 如果願意,請參閱coalesce 標量 function或使用ifnull 標量 function ,它們的工作方式相同,只是合並更靈活一點,而不是在這種情況下需要靈活性。

    • coalesce 更明顯,因此使用而不是 ifnull。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM