全新安装 Appcelerator Alloy 迁移抛出 SQL 错误

Appcelerator Alloy migration throwing SQL error when app is freshly installed

在我的应用程序中,我有一个包含一些列的模型,需要添加一个新列。

所以根据 documentation 我写了一个带有 SQL "alter table add column.." 的迁移文件并将 属性 添加到 alloy 模型文件中.正如预期的那样,这非常有效。

但是,当该应用程序首次安装在设备上时,会抛出 SQL 错误,指出我的迁移尝试添加的列已经存在。由于数据库模式是从模型文件创建的,我猜这个例外是正确的,但我想知道如何为现有和新安装的应用程序完成数据库更改。删除迁移文件,只需将 属性 添加到模型文件即可使其适用于全新安装,但不适用于更新。

此致, 斯文

更新 1: 我尝试添加一个初始迁移,创建 table 没有新字段,然后在另一个迁移中添加新字段(参见 Ray 的回答)。还是一样的错误。

Appcelerator 版本:5.2.2

模型适配器类型:sqlrest

更新 2(一些代码):

型号:

config: {
URL: Alloy.Globals.jsonEndPoint + Alloy.Globals.jsonRequestParams + "foto",
columns:{
    id:                                     "INTEGER PRIMARY KEY AUTOINCREMENT",
    dateiname:                              "TEXT",
    beschreibung:                           "TEXT",
    primaerfoto:                            "TEXT",
    aufnahmedatum:                          "TEXT",
    anlage_id:                              "INTEGER",
    foto_label_id:                          "INTEGER",
    latest_sync_date:                       "TEXT",
    dirty:                                  "INTEGER",
    begehungsbericht_protokoll_id:          "INTEGER",          
    begehungsbericht_protokoll_server_id:   "INTEGER",          
},
adapter: {
    remoteBackup: false,                        //Prevent database from being saved in icloud   
    db_name: this.Alloy.Globals.currentDatabase,
    type: "sqlrest",
    collection_name: "foto",
    idAttribute: "id"
}

迁移 1:

migration.up = function(migrator) {
Ti.API.info(">>>>>>>>>>>>>>>> migrate create table UP <<<<<<<<<<<<<");
migrator.createTable({
    columns: {
        id:                                     "INTEGER PRIMARY KEY AUTOINCREMENT",
        dateiname:                              "TEXT",
        beschreibung:                           "TEXT",
        primaerfoto:                            "TEXT",
        aufnahmedatum:                          "TEXT",
        anlage_id:                              "INTEGER",
        foto_label_id:                          "INTEGER",
        latest_sync_date:                       "TEXT",
        dirty:                                  "INTEGER",
        begehungsbericht_protokoll_id:          "INTEGER",
    }
});

迁移 2:

migration.up = function(migrator) {
Ti.API.info(">>>>>>>>>>>>>>>> migrate ALTER table UP <<<<<<<<<<<<<");
migrator.db.execute('ALTER TABLE foto ADD COLUMN begehungsbericht_protokoll_server_id INTEGER;');

};

更新 3(具有变通方法的解决方案): 因为我知道在 运行 迁移时 table 应该有的列数,所以我使用此信息有条件地添加列(如 Cesar 提议的那样)。

migration.up = function(migrator) {
Ti.API.info("migrating foto table");

var rows = migrator.db.execute("SELECT * FROM foto");
Ti.API.info("field count: " + rows.fieldCount);

if (rows.fieldCount < 11) {
    Ti.API.info("adding column: begehungsbericht_protokoll_server_id");
    migrator.db.execute('ALTER TABLE foto ADD COLUMN begehungsbericht_protokoll_server_id INTEGER');
} else {
    Ti.API.info("NOT adding column: begehungsbericht_protokoll_server_id");
} 

};

数据库迁移始终是应用程序开发中的一个复杂部分。也就是说,有利有弊,在某些时候会让您清除整个数据库并从头开始进行主要更新。

好处 是您应该能够检查该列是否存在,方法是在 migration.up 中执行一个简单的 SELECT函数并使用 http://docs.appcelerator.com/platform/latest/#!/api/Titanium.Database.ResultSet-method-isValidRow

验证查询是否成功

您还可以 "version" 您的数据库,方法是在对数据库架构所做的每次更改中添加一个 Alloy.Globals 属性。类似于 Alloy.Globals.DatabaseVersion = 1 并在您的 migration.upmigration.down 函数中验证它,这样您至少知道您在当前数据库模式中的位置以及您希望在迁移的数据库模式中的位置.

not-so-good 的事情是,每次更改时,您都必须编写代码来管理所有可能的用例(例如,版本 1 的用户跳转到版本3 没有去 2) 所以边走边想。

Sven,首先检查一下:https://medium.com/all-titanium/using-models-and-migrations-in-titanium-a03e3a6b0d6f#.2qb9oj3rh

我认为您遇到的问题是您需要进行初始迁移,使用 createTable 设置原始模型。然后应用迁移。 应该 有效。