“PRAGMAforeign_keys=OFF”SQLite 语句可以在 TypeORM 迁移中使用吗?

chi*_*7CC 3 sqlite foreign-keys typeorm

我使用 TypeORM (v0.2.18) 和 Node.js (v12.7.0) 在 SQLite 数据库中执行迁移。

这是我的情况:我有一个名为 的表country和一个名为 的表workflow。我想删除其中一列名为 的列namecountry但通过该列进行workflow引用country

使用 SQLite 的 DB Browser,我可以使用以下语句成功删除该列:

PRAGMA foreign_keys=OFF;
CREATE TEMPORARY TABLE country_backup(id, createdAt, updatedAt, enabled, codeIso2);
INSERT INTO country_backup SELECT id, createdAt, updatedAt, enabled, codeIso2 FROM country;
DROP TABLE country;
CREATE TABLE country(id, createdAt, updatedAt, enabled, codeIso2);
INSERT INTO country SELECT id, createdAt, updatedAt, enabled, codeIso2 FROM country_backup;
DROP TABLE country_backup;
PRAGMA foreign_keys=ON;
Run Code Online (Sandbox Code Playgroud)

我在 TypeORM 迁移中使用了它,如下所示:

...
public async up(queryRunner: QueryRunner): Promise<any> {
    await queryRunner.query("PRAGMA foreign_keys=OFF");
    await queryRunner.query("CREATE TEMPORARY TABLE country_backup(id, createdAt, updatedAt, enabled, codeIso2)");
    await queryRunner.query("INSERT INTO country_backup SELECT id, createdAt, updatedAt, enabled, codeIso2 FROM country");
    await queryRunner.query("DROP TABLE country");
    await queryRunner.query("CREATE TABLE country(id, createdAt, updatedAt, enabled, codeIso2)");
    await queryRunner.query("INSERT INTO country SELECT id, createdAt, updatedAt, enabled, codeIso2 FROM country_backup");
    await queryRunner.query("DROP TABLE country_backup");
    await queryRunner.query("PRAGMA foreign_keys=ON");
}
...
Run Code Online (Sandbox Code Playgroud)

但我收到这个错误:

Error during migration run:
QueryFailedError: SQLITE_CONSTRAINT: FOREIGN KEY constraint failed
    at new QueryFailedError (/.../api/src/error/QueryFailedError.ts:9:9)
    at Statement.handler (/.../src/driver/sqlite/SqliteQueryRunner.ts:53:26)
    at Statement.replacement (/.../api/node_modules/sqlite3/lib/trace.js:19:31)
    at Statement.replacement (/.../api/node_modules/sqlite3/lib/trace.js:19:31) {
  message: 'SQLITE_CONSTRAINT: FOREIGN KEY constraint failed',
  errno: 19,
  code: 'SQLITE_CONSTRAINT',
  name: 'QueryFailedError',
  query: 'DROP TABLE country',
  parameters: []
}
Run Code Online (Sandbox Code Playgroud)

为什么它可以在 SQLite 的 DB Browser 中工作,但不能在 TypeORM 中工作?就像它忽略了 PRAGMA 语句一样。

基于,我尝试同时使用PRAGMA foreign_keysand PRAGMA legacy_alter_table(分别将它们设置为 OFF 和 ON(在任何操作之前)以及 ON 和 OFF(在任何操作之后))。

up()我尝试在函数内部和外部使用 PRAGMA 。外部意味着我将之前和之后的语句放入await typeOrmConnection.runMigrations()我的文件中main.ts,例如await typeOrmConnection.query("PRAGMA foreign_keys=OFF").

小智 5

sqlite 文档说您无法PRAGMA foreign_keys=off在执行多个语句时进行设置,因此我尝试了这一点,并通过将 PRAGMA 语句与其他语句分开来使其工作。

已为传递给函数的查询运行器实例启动事务up()。因此,请立即结束现有事务,然后使用事务外查询关闭检查,然后启动另一个事务。

在新事务中写入其余的非 PRAGMA 代码。

在函数结束之前,提交内部事务,然后使用常规的单语句查询重新打开关键检查,然后启动另一个事务(这样运行后就会有一些东西自动关闭up(),否则你会得到一个错误)。

public async up(queryRunner: QueryRunner): Promise<any> {
    await queryRunner.commitTransaction();
    await queryRunner.query('PRAGMA foreign_keys=off');
    await queryRunner.startTransaction();

    // the rest of your queries

    await queryRunner.commitTransaction();
    await queryRunner.query('PRAGMA foreign_keys=on');
    await queryRunner.startTransaction();
}

Run Code Online (Sandbox Code Playgroud)