Миграция Appcelerator Alloy вызывает ошибку SQL, когда приложение только что установлено

в моем приложении у меня есть модель с некоторыми столбцами, в которую нужно добавить новый столбец.

Итак, согласно документация Я написал файл миграции с SQL «изменить таблицу добавить столбец..» и также добавил это свойство в файл модели сплава. Как и ожидалось, это сработало отлично.

Но когда приложение устанавливается на устройство в первый раз, возникает ошибка SQL, говорящая о том, что столбец, который пытается добавить моя миграция, уже существует. Поскольку схема базы данных создается из файлов модели, я думаю, что исключение правильное, но мне интересно, как выполнить изменение базы данных для существующих и недавно установленных приложений. Удаление файла миграции, просто добавление свойства в файл модели заставит его работать при новой установке, но не при обновлениях.

С уважением, Свен

Обновление 1: я попытался добавить первоначальную миграцию, создав таблицу без нового поля, а затем добавив новое поле в другую миграцию (см. ответ Рэя). Все та же ошибка.

Версия 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 (решение с обходным путем): Поскольку я знаю количество столбцов, которые должна иметь таблица при выполнении переноса, я использую эту информацию для условного добавления столбца (как предложил Цезарь).

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");
} 

};


person Sven    schedule 23.01.2017    source источник
comment
Добавлено обходное решение, основанное на ответе Цезаря. Не нравится это слишком много, но на данный момент все в порядке.   -  person Sven    schedule 24.01.2017
comment
Кстати, миграция 1 в моем случае не нужна!   -  person Sven    schedule 24.01.2017
comment
Интересно, правильно ли работает миграция SQLRest? Проблема с нестандартным адаптером в том, что он может работать не так, как другие...   -  person Ray    schedule 25.01.2017


Ответы (2)


Миграция БД всегда является сложной частью разработки приложений. Тем не менее, есть плюсы и минусы, которые в какой-то момент заставят вас стереть всю БД и начать с нуля основные обновления.

Хорошая вещь заключается в том, что вы должны иметь возможность проверить, существует ли столбец или нет, либо выполнив простую операцию SELECT в функции migration.up, либо проверив успешность запроса с помощью http://docs.appcelerator.com/platform/latest/#!/api/Titanium.Database.ResultSet-method-isValidRow

Вы также можете «версировать» свою БД, добавляя один атрибут Alloy.Globals при каждом изменении, которое вы делаете в схеме БД. Что-то вроде Alloy.Globals.DatabaseVersion = 1 и подтвердите это в своих функциях migration.up и migration.down, таким образом вы, по крайней мере, будете знать, где вы находитесь в вашей текущей схеме БД и где вы хотите быть в вашей перенесенной схеме БД.

Не так уж хорошо то, что с каждым изменением вам придется писать код для управления всеми возможными вариантами использования (например, пользователь с версией 1 переходит к версии 3, не переходя к версии 2), так что подумайте об этом также, как вы идете.

person Cesar Cavazos    schedule 23.01.2017
comment
Спасибо за ваш комментарий. На самом деле миграции отлично работают для меня в других проектах (Java, flyway). Проблема здесь в том, что я не вижу никакого правила для порядка установки и переноса базы данных. Самостоятельное управление версиями базы данных для меня не вариант, так как это единственное, чего я ожидаю от среды миграции;) Я проверю обходной путь с помощью функции isValidRow и сообщу о результате здесь. - person Sven; 24.01.2017
comment
Обновлен первоначальный вопрос с обходным решением на основе вашего предложения. Спасибо. - person Sven; 24.01.2017
comment
Я рад, что это помогло вам. Лично я стараюсь держаться подальше от разрешающих моделей, поскольку API, которые я вызываю в своих проектах, более сложны, чем то, что могут сделать адаптеры. Я также использую joli для управления локальными базами данных, и это работает очень хорошо. - person Cesar Cavazos; 24.01.2017

Свен, прежде всего, проверьте это: https://medium.com/all-titanium/using-models-and-migrations-in-titanium-a03e3a6b0d6f#.2qb9oj3rh

Я думаю, что проблема, с которой вы столкнулись, заключается в том, что вам нужна первоначальная миграция с исходной настройкой модели с использованием createTable. Затем примените миграцию. Это должно работать.

Рэй

person Ray    schedule 24.01.2017
comment
Рэй, спасибо за ссылку. Я читал об этом первоначальном файле миграции раньше, и он у меня не работает. Странная вещь: миграция createTable выполняется без каких-либо исключений, поэтому я ожидаю, что таблицы раньше не было. Следующая миграция (добавление нового столбца) завершается сбоем из-за нарушения дублирования столбца. На самом деле я не вижу никакого правила, в котором выполняются миграции/создание схемы из модели. Я обновлю первоначальный вопрос, добавив дополнительную информацию о версии appcelerator и соединителе. - person Sven; 24.01.2017
comment
Возможно, публикация вашей модели и миграции тоже поможет. - person Ray; 24.01.2017