4

我正在编写一个严重依赖本地存储的 React-Native 应用程序,并选择了 TypeORM来处理这个问题。

我现在进入了我的项目正在运行的阶段,我想添加需要调整我的数据模型的新功能。首先,我使用了 react-native-example 项目。我已经在此基础上构建了我的数据模型,现在想实现向其中的迁移。

似乎没有关于如何在 React-Native 上执行迁移的明确手册/指南。由于我无权访问用户的数据库,因此无法手动运行迁移。到目前为止,我发现连接设置中有一个“migrationsRun”选项可以设置为 true,如果需要,在每次启动应用程序时强制执行迁移。

那么问题是:应该如何创建实际的迁移,它们应该是什么样的(普通的 sql 查询?),我应该把它们放在哪里?

任何有关在 react-native 应用程序中迁移的指导都会非常有帮助。

4

1 回答 1

6

createConnection我遇到了同样的问题,并通过提供以下属性作为选项,设法让迁移在反应本机上下文中运行:

  • 同步: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而且我在直接导入文件时必须添加

似乎让它在 react-native 中工作的主要(几乎)未记录的发现是migrationsRun我在这里发现的神奇属性reactnativeconnectionoptions

随着时间的推移,您可以migrations根据需要将更多迁移文件添加到阵列配置中,并确保为它们提供具有适当时间戳的唯一类名。它似乎保留了已运行迁移的设备日志 - 以阻止它们在同一设备上多次运行

注意:要求synchronize: false意味着您需要在首次安装应用程序时对架构进行初始同步(我最初使用 AsyncStorage 中的标志设置以指示首次应用程序安装)

替代方法

上述方法意味着我们在初始用户安装后手动维护我们的架构设置。而我非常喜欢在可能的情况下自动管理架构的想法 - 迁移仅用于操作数据。

因此,实现此目的的另一种方法是在初始化连接时直接调用synchronizeand方法。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')
    }
  }
}

于 2020-01-23T21:48:29.490 回答