【问题标题】:Can "PRAGMA foreign_keys=OFF" SQLite statement be used inside a TypeORM migration?可以在 TypeORM 迁移中使用“PRAGMA foreign_keys=OFF”SQLite 语句吗?
【发布时间】:2020-03-19 13:09:52
【问题描述】:

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

这是我的情况:我有一个名为 country 的表和一个名为 workflow 的表。我想删除country 中名为name 的列之一,但workflow 通过此列引用country。

使用 DB Browser for SQLite 我可以使用这些语句成功删除该列:

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;

我在这样的 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");
}
...

但我收到此错误:

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: []
}

为什么它在 SQLite 的 DB Browser 中有效,但在 TypeORM 中无效?就像它忽略了 PRAGMA 语句。

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

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

【问题讨论】:

  • 这个问题好运吗? :)

标签: sqlite foreign-keys typeorm


【解决方案1】:

sqlite 文档说你不能在执行多个语句时设置PRAGMA foreign_keys=off,所以我尝试了这个并通过将 PRAGMA 语句与其他语句分开来使其工作。

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

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

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

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();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-14
    • 2012-11-22
    • 1970-01-01
    • 1970-01-01
    • 2023-01-17
    • 1970-01-01
    • 2012-03-29
    • 1970-01-01
    相关资源
    最近更新 更多