具有 4 个数据库版本的 SQLite onUpgrade

SQLite onUpgrade with 4 database versions

当我们有 4 个数据库版本并且我们在每个版本中为用户 table 添加了一个新字段时,执行 SQLiteOpenHelper 的 onUpgrade 方法的正确方法是什么?

变体 A:// 每个案例后没有 "break",案例 2 和案例 3 是否保持 运行?

public void onUpgrade(SQLiteDatabase database, int version_old, int current_version) {
    switch (version_old) {
    case 1:
        database.execSQL(addPostcodeFieldToUserTable);
    case 2:
        database.execSQL(addGenderFieldToUserTable);
    case 3:
        database.execSQL(addEmailSubscriptionFieldToUserTable);
        break;
    }
}

变体 B:

public void onUpgrade(SQLiteDatabase database, int version_old, int current_version) {
    switch (version_old) {
    case 1:
        database.execSQL(addPostcodeFieldToUserTable);
        break;
    case 2:
        database.execSQL(addPostcodeFieldToUserTable);
        database.execSQL(addGenderFieldToUserTable);
        break;
    case 3:
        database.execSQL(addPostcodeFieldToUserTable);
        database.execSQL(addGenderFieldToUserTable);
        database.execSQL(addEmailSubscriptionFieldToUserTable);
        break;
    }

但是,如果用户拥有第 1 版数据库,然后错过第 2 版并使用第 3 版升级应用程序,我们该怎么办?

变体 3:

public void onUpgrade(SQLiteDatabase database, int version_old, int current_version) {
    if(version_old==1 && current_version==2) {
        database.execSQL(addPostcodeFieldToUserTable);

    } else if(version_old==2 && current_version==3) {
        database.execSQL(addGenderFieldToUserTable);

    } else if(version_old==3 && current_version==4) {
        database.execSQL(addEmailSubscriptionFieldToUserTable);

    } else if(version_old==1 && current_version==3) {
        database.execSQL(addPostcodeFieldToUserTable);
        database.execSQL(addGenderFieldToUserTable);

    } else if(version_old==1 && current_version==4) {
        database.execSQL(addPostcodeFieldToUserTable);
        database.execSQL(addGenderFieldToUserTable);
        database.execSQL(addEmailSubscriptionFieldToUserTable);

    } else if(version_old==2 && current_version==4) {
        database.execSQL(addGenderFieldToUserTable);
        database.execSQL(addEmailSubscriptionFieldToUserTable);

    }
}

你还可以做的是使 onUpgrade 成为一个递归调用,

public void onUpgrade(SQLiteDatabase database, int version_old, int current_version) {
switch (version_old) {
case 1:
    database.execSQL(addPostcodeFieldToUserTable);
    onUpgrade(database,version_old++,current_version);
    break;
case 2:
    database.execSQL(addPostcodeFieldToUserTable);
    database.execSQL(addGenderFieldToUserTable);
    onUpgrade(database,version_old++,current_version)
    break;
default:
    break;
}

你明白了,所以它会升级到最新版本并停止调用自己。

No "break" after each case, does it keep running for case 2 and 3?

是的。通常的做法是添加评论,例如

// fallthrough

表示遗漏break是故意的。

But what do we do in the case when a user had version 1 of the DB, then missed version 2 and upgraded the app with version 3?

onUprade() 将使用 oldVersion 1 和 newVersion 3 调用。代码应将数据库更新到架构的版本 3。

使用哪个变体取决于哪个对您来说维护起来最舒服。我个人会选择变体 A 之类的东西,因为它的代码最少。

在没有 break 的情况下使用 switch 是违反直觉的。

一个常见的模式是使用一系列 if 代替:

if (version_old < 2) {
    database.execSQL(addPostcodeFieldToUserTable);
}
if (version_old < 3) {
    database.execSQL(addGenderFieldToUserTable);
}
if (version_old < 4) {
    database.execSQL(addEmailSubscriptionFieldToUserTable);
}