我目前正在尝试使用PersistenceJS的迁移插件对现有数据库进行更改。我可以在DB中添加/编辑/删除项目,但是......
如何更改现有(!)列的类型,例如来自' text'到'整数'?
These changes should retain currently existing data.
可悲的是,文档有点稀缺,也许你可以帮忙吗?
以下是正常工作设置:
persistence.store.websql.config(persistence, 'tododatabase', 'todos are fun', 5*1024*1024);
var Todo = persistence.define('Todo', {
task: 'TEXT',
priority: 'INT',
done: 'BOOL'
});
persistence.schemaSync();
function addTodo( item ){
var todo = new Todo();
todo.task = item.task;
todo.priority = item.priority;
todo.done = item.done;
persistence.add(todo);
persistence.flush();
};
function deleteTodo( item, callback ){
// item.id was created automatically by calling "new Todo()"
Todo.all().filter('id','=', item.id ).destroyAll( function(){
persistence.flush( callback );
});
};
有点的迁移代码:
persistence.defineMigration(1, {
up: function() {
this.createTable('Todo', function(t){
t.text('task');
t.integer('priority');
t.boolean('done');
});
},
down: function() {
this.dropTable('Todo');
}
});
persistence.defineMigration(2, {
up: function() {
this.addColumn('Todo', 'due', 'DATE');
},
down: function() {
this.removeColumn('Todo', 'due');
}
});
function migrate( callback ){
console.log('migrating...');
persistence.migrations.init( function(){
console.log('migration init');
// this should migrate up to the latest version, in our case: 2
persistence.migrate( function(){
console.log('migration complete!');
} );
});
}
persistence.store.websql.config(persistence, 'newdatabase', 'testing migration', 5*1024*1024);
,不调用schemaSync(),只调用migrate()将成功记录"迁移完成!" - 但它是在一个新的,完全空的数据库" newdatabase"中实现的,当然不会保留任何现有数据。使用persistence.store.websql.config(...)
,persistence.define('Todo',...)
和persistence.schemaSync()
创建了一个数据库。
我现在想要保留该数据库中已存在的所有数据,但希望
priority
的类型到'文字' due
所有现有的Todos 如果你能把我推向正确的方向,我会非常感激!
谢谢!
答案 0 :(得分:5)
我终于开始工作了。我的初始要求存在许多问题,我想指出以供将来参考。看一下第一个迁移定义:
persistence.defineMigration(1, {
up: function() {
this.createTable('Todo', function(t){
...
毫不奇怪,createTable
将完全执行以下操作:它将执行SQL语句'CREATE TABLE Todo ...'
,如果已存在名称为Todo
的表,它将静默失败并停止迁移。这就是为什么它适用于新数据库,而不是现有数据库。请记住:我已经拥有一个带有表格的实时数据库" Todo"需要更新。如果你重新开始(即你没有使用schemaSync
),createTable
就可以了。由于迁移插件不提供createTableIfNotExists
方法,因此我需要使用executeSql
,如下所示:
persistence.defineMigration(1, {
up: function() {
this.executeSql('CREATE TABLE IF NOT EXISTS Todo (id VARCHAR(32) PRIMARY KEY, task TEXT, priority INT, done BOOL)');
...
既然从模式版本0到1的迁移成功,那么迁移到版本2也是成功的。
迁移到版本3时,priority
列的类型需要从int
更改为text
。这通常使用ALTER COLUMN
SQL命令完成,Web SQL / SQLite不支持。请参阅 Omitted Features for SQLite 。
使用SQLite更改列需要一个4步骤的解决方法:
persistence.defineMigration(3, {
up: function() {
// rename current table
this.executeSql('ALTER TABLE Todo RENAME TO OldTodo');
// create new table with required columns and column types
this.executeSql('CREATE TABLE Todo (id VARCHAR(32) PRIMARY KEY, task TEXT, priority TEXT, done BOOL)');
// copy contents from old table to new table
this.executeSql('INSERT INTO Todo(id, task, priority, done) SELECT id, task, priority, done FROM OldTodo');
// delete old table
this.executeSql('DROP TABLE OldTodo');
},
...
当然,在更改列类型后,' Todo'的实体定义也应该改变:
var Todo = persistence.define('Todo', {
task: 'TEXT',
priority: 'TEXT', // was 'INT'
due: 'DATE',
done: 'BOOL'
});
persistence.store.websql.config(persistence, 'tododatabase', 'todos are fun', 5*1024*1024);
// persistence.debug = true;
//v0 + v1
// var Todo = persistence.define('Todo', {
// task: 'TEXT',
// priority: 'INT',
// done: 'BOOL'
// });
//v2
// var Todo = persistence.define('Todo', {
// task: 'TEXT',
// priority: 'INT',
// due: 'DATE',
// done: 'BOOL'
// });
//v3
var Todo = persistence.define('Todo', {
task: 'TEXT',
priority: 'TEXT',
due: 'DATE',
done: 'BOOL'
});
persistence.defineMigration(1, {
up: function() {
this.executeSql('CREATE TABLE IF NOT EXISTS Todo (id VARCHAR(32) PRIMARY KEY, task TEXT, priority INT, done BOOL)');
},
down: function() {
this.dropTable('Todo');
}
});
persistence.defineMigration(2, {
up: function() {
this.addColumn('Todo', 'due', 'DATE');
},
down: function() {
this.removeColumn('Todo', 'due');
}
});
persistence.defineMigration(3, {
up: function() {
// rename current table
this.executeSql('ALTER TABLE Todo RENAME TO OldTodo');
// create new table with required columns
this.executeSql('CREATE TABLE Todo (id VARCHAR(32) PRIMARY KEY, task TEXT, priority TEXT, due DATE, done BOOL)');
// copy contents from old table to new table
this.executeSql('INSERT INTO Todo(id, task, priority, due, done) SELECT id, task, priority, due, done FROM OldTodo');
// delete current table
this.executeSql('DROP TABLE OldTodo');
},
down: function() {
this.executeSql('ALTER TABLE Todo RENAME TO OldTodo');
this.executeSql('CREATE TABLE Todo (id VARCHAR(32) PRIMARY KEY, task TEXT, priority INT, due DATE, done BOOL)');
this.executeSql('INSERT INTO Todo(id, task, priority, due, done) SELECT id, task, priority, due, done FROM OldTodo');
this.executeSql('DROP TABLE OldTodo');
}
});
function migrate( callback ){
console.log('migrating...');
persistence.migrations.init( function(){
console.log('migration init');
persistence.migrate( function(){
console.debug('migration complete!');
callback();
} );
});
};
migrate( onMigrationComplete );
function onMigrationComplete(){
// database is ready. do amazing things...
};
答案 1 :(得分:2)
这是一个很好的解释,谢谢!但我想我知道一种更简单的方法来实现这一目标。
我遇到了和你一样的麻烦:我有一组用persistence.define
描述并用persistence.schemaSync
创建的模式。
所以这是我的特例:
// This is my mixin for all schemas
var Versioned = persistence.defineMixin('Versioned', {
serverId: "TEXT",
intVersion: "INT",
dtSynced: "DATE",
dtCreatedAt: "DATE",
dtUpdatedAt: "DATE",
delete: "BOOL",
update: "BOOL",
add: "BOOL",
isReadOnly: "BOOL"
});
// This is one of the schemas I need to update with a new field.
var Person = persistence.define('Person', {
fullName: "TEXT",
rate: "INT"
});
//... More schema definitions
// Setup mixin
Person.is(Versioned);
// Sync schemas
persistence.schemaSync();
确定。没什么特别的。现在几个月后我的应用程序正在投入生产中,我想在isEmployed
架构中添加一个新字段Person
。
根据文档,我应该将所有模式定义重写为迁移并停止使用persistence.schemaSync()
。但我不想重写我的所有定义。而不是我在PersistenceJS init代码后面定义一个新的迁移:
// Init ORM
persistence.store.websql.config(
persistence,
'Sarafan',
'0.0.2',
'Sarafan.app database',
100 * 1024 * 1024,
0
);
// Define Migrations
persistence.defineMigration(1, {
up: function () {
this.addColumn('Person', 'isEmployed', 'BOOL');
}
});
// ... describing isVersioned mixin
// Updated schema definition with a new field 'isEmployed'
var Person = persistence.define('Person', {
fullName: "TEXT",
rate: "INT",
isEmployed: "BOOL"
});
//... More schema definitions
// Setup mixin
Person.is(Versioned);
// Apply the migration right away from the schemaSync call.
persistence.schemaSync(function (tx) {
persistence.migrations.init(function () {
persistence.migrate(function(){
// Optional callback to be executed after initialization
});
});
});
就是这样!我测试了这种方法只是为了向模式添加新字段。
让我知道它是否对您有效。