我已经在react-native和expo中开发了一个android应用。我还已经在Google Play上发布了该应用。
现在,我在本地对SQLite DB表进行了一些修改。
假设在表的架构之前是这样的:
CREATE TABLE expenditures (id integer primary key, max_amount REAL not null);
现在我想将其更改为:
CREATE TABLE expenditures (id integer primary key, max_amount TEXT not null);
在生产应用(Google Play商店)上进行新的更新/升级后,是否有任何方法可以运行方法?这样,升级后我只能更改一次表,其他新安装的用户将不受此功能的影响。我在本机android上找到了两种方法:
但是,由于我已经使用react-native和expo开发了我的应用程序,因此无法使用上述方法。尽管我发现了onUpgrade
in the expo code,但不确定如何在Expo中使用此功能。
或者有什么更好的方法可以在react-native和expo中处理已发布应用程序上的数据库迁移?
答案 0 :(得分:1)
我认为您不能真正使用链接到的版本控制内容,因为这将删除您的数据库并从头开始重新创建它,因此您将丢失数据。
一个简单的解决方案是手动跟踪表中已经执行的迁移。然后,您可以创建该表(如果该表尚不存在)(可以通过非常笨拙的方式来进行操作,首先尝试查询它,如果失败,则创建它)。如果您按顺序列出了所有已知的迁移,则可以删除表中已有条目的项目,然后运行其余的条目。
我从一个旧的Cordova应用程序中编写了此代码(是的,它确实很旧,它仍在使用Require JS来定义模块):
/**
* Provide access to an SQL database, using the SQLite plugin for
* Cordova devices so we aren't limited in how much data we can store,
* and falling back to browser native support on desktop.
*
* Unfortunately webSQL is deprecated and slowly being phased out.
*/
define(['require', 'module', 'deviceReady!'], function(require, module, isCordova) {
'use strict';
var dbRootObject = isCordova ? window.sqlitePlugin : window,
config = module.config();
if (typeof dbRootObject.openDatabase == 'undefined') {
window.alert('Your browser has no SQL support! Please try a Webkit-based browser');
return null;
} else {
var db = dbRootObject.openDatabase(config.dbName, '', 'Direct Result database', null),
transaction = function(callback) {
// We go through this trouble to automatically provide
// error reporting and auto-rollback.
var makeFacade = function(t) {
return {
sql: function(sql, args, okCallback, errorCallback) {
var okFn, errFn;
if (okCallback) {
okFn = function(t, r) { return okCallback(makeFacade(t), r); };
} else {
okFn = null;
}
if (errorCallback) {
errFn = function(t, e) { console.log('SQL error: '+sql, e); return errorCallback(makeFacade(t), e); };
} else {
errFn = function(t, e) {
// It's important we throw an exn,
// else the txn won't be aborted!
window.alert(e.message + ' sql: '+sql);
throw(e.message + ' sql: '+sql);
};
}
return t.executeSql(sql, args, okFn, errFn);
}
};
};
return db.transaction(function(t) {
return callback(makeFacade(t));
}, function(e) { console.log('error'); console.log(e); });
},
// We're going to have to create or own migrations, because
// both the Cordova SQLite plugin and the Firefox WebSQL
// extension don't implement versioning in their WebSQL API.
migrate = function(version, upFn, done, txn) { // "Down" migrations are currently not supported
var doIt = function(t) {
t.sql('SELECT NOT EXISTS (SELECT version FROM sqldb_migrations WHERE version = ?) AS missing',
[version], function(t, r) {
if (r.rows.item(0).missing == '1') {
upFn(t, function() {
t.sql('INSERT INTO sqldb_migrations (version)'+
'VALUES (?)', [version], done);
});
} else {
done(t);
}
});
};
if (txn) doIt(txn);
else transaction(doIt);
},
maybeRunMigrations = function(callback) {
var migrations = [],
addMigration = function(name, migration) {
migrations.push([name, migration]);
},
runMigrations = function(t) {
if (migrations.length === 0) {
callback(t);
} else {
var m = migrations.shift(),
name = m[0],
migration = m[1];
migrate(name, migration, runMigrations, t);
}
};
// ADD MIGRATIONS HERE. The idea is you can just add migrations
// in a queue and they'll be run in sequence.
// Here are two example migrations
addMigration('1', function (t, done) {
t.sql('CREATE TABLE people ('+
' id integer PRIMARY KEY NOT NULL, '+
' initials text NOT NULL, '+
' first_name text NOT NULL, '+
' family_name text NOT NULL, '+
' email text NOT NULL, ', [], done);
});
addMigration('2', function(t, done) {
t.sql('ALTER TABLE people ADD COLUMN phone_number text', [], done);
});
transaction(function(t) {
t.sql('CREATE TABLE IF NOT EXISTS sqldb_migrations ('+
' version int UNIQUE, '+
' timestamp_applied text NOT NULL DEFAULT CURRENT_TIMESTAMP '+
')', [], function (t, r) { runMigrations(t, migrations); });
});
};
// Expose "migrate" just in case
return {transaction: transaction, migrate: migrate, maybeRunMigrations: maybeRunMigrations};
}
});
您还需要格外小心,因为我发现很难用SQLite(或至少在我编写此代码时不使用Cordova插件)更改或删除列的困难方式!因此,也要特别注意约束条件,否则您最终会陷入困境。
我还没有尝试过,但是如果您重命名旧表,使用更改后的列再次创建新表,然后复制数据,则有可能。
答案 1 :(得分:0)
您可以将sql更改文件放在资产文件夹android / app / src / main / assets /之类的
<version>.sql -> 1.sql or 2.sql
,这些文件可以包含迁移查询,例如
alter table NOTE add NAME TEXT;
并根据onUpgrade()方法中应用程序的版本触发这些查询