我正在编写一个React-Native应用程序,该应用程序高度依赖本地存储,并选择TypeORM来处理此问题。
我现在正在进入一个项目正在运行的阶段,我想添加新功能,这些功能需要调整我的数据模型。首先,我使用了react-native-example项目。我已经在此基础上建立了数据模型,现在想对其进行移植。
关于如何在React-Native上执行迁移,似乎没有权威的手册/指南。 由于我无权访问用户的数据库,因此无法手动运行迁移。到目前为止,我发现连接设置中有一个“ migrationsRun”选项,可以将其设置为true,从而在需要启动应用程序时强制执行迁移。
然后的问题是:应该如何创建实际的迁移,它们的外观如何(普通sql查询?),我应该在哪里放置它们?
任何有关本机应用程序中迁移的指南都将非常有帮助。
答案 0 :(得分:4)
我遇到了同样的问题,并通过提供以下属性作为createConnection
选项,设法使迁移在React Native上下文中运行:
false
true
migrationFile
] migrationFile
是直接导入的(而不是使用文件路径正则表达式),其外观类似于以下内容(带有内联SQL语句):
import { MigrationInterface } from 'typeorm'
module.exports = class PostRefactoring1579804977343 implements MigrationInterface {
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "workouts" ADD COLUMN "questionSetId" text`)
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "workouts" DROP COLUMN "questionSetId"`)
}
}
上面的迁移文件看起来与您在https://typeorm.io/#/migrations上看到的示例略有不同,因为我没有使用TypeScript,而且在直接导入文件时必须添加module.exports
主要(几乎)未记录的发现,似乎使它可以在本机中工作,是我在这里reactnativeconnectionoptions发现的神奇的migrationsRun
您可以根据需要将更多的迁移文件随时间添加到migrations
阵列配置中,并确保为它们提供具有适当时间戳的唯一类名称。似乎保留了已运行迁移的设备日志-阻止它们在同一设备上运行多次
注意:具有synchronize: false
的要求意味着您将需要在首次安装应用程序时进行模式的初始同步(我最初使用AsyncStorage中的标志将其设置为指示首次安装应用程序)< / p>
替代方法
以上方法意味着我们将在初始用户安装后手动维护架构设置。而我非常喜欢在可能的情况下自动管理架构的想法-迁移仅用于处理数据。
因此,实现此目标的另一种方法是在初始化连接时直接调用synchronize
和runMigrations
方法。在这种情况下,您将需要首先检查迁移脚本中是否存在特定的表,因为它们将首先运行,因此,如果这是用户在安装后第一次打开应用程序,则需要更新的表可能不存在
连接选项:
export const initialiseDataStoreService = async () => {
const connection = await createConnection({
type: 'react-native',
database: 'main.sqlite',
location: 'default',
logging: [ 'error', 'schema'],
entities: [
CoreData,
Workouts,
],
migrations: [PostRefactoring1579804977343],
})
await connection.runMigrations()
await connection.synchronize()
return connection
}
更新的迁移脚本:
import { MigrationInterface, TableColumn } from 'typeorm'
module.exports = class PostRefactoring1579804977343 implements MigrationInterface {
async up(queryRunner) {
const hasWorkoutsTable = await queryRunner.hasTable('workouts')
if (hasWorkoutsTable) {
await queryRunner.addColumn(
'workouts',
new TableColumn({
name: 'questionSetId',
type: 'text',
// we make the new field nullable in order to enable the update
// for existing data (schema sync will later update this column to be non
// nullable)
isNullable: true,
}),
)
await queryRunner.query(
`UPDATE workouts SET questionSetId = "MIGRATION-PLACEHOLDER" WHERE questionSetId IS NULL`,
)
}
}
async down(queryRunner) {
const hasWorkoutsTable = await queryRunner.hasTable('workouts')
if (hasWorkoutsTable) {
await queryRunner.dropColumn('workouts', 'questionSetId')
}
}
}