TypeORM结合SQLite启动时未创建Account表,执行迁移报错求助
解决TypeORM启动时迁移执行提示表不存在的问题
问题原因
你的配置同时开启了synchronize: true和migrationsRun: true,但TypeORM的执行顺序是先运行迁移,再执行synchronize同步表结构。所以当迁移代码尝试查询account表时,synchronize还没来得及创建这个表,就会抛出“表不存在”的错误。
另外,官方不建议同时使用synchronize和迁移机制:synchronize仅适合开发环境快速同步表结构,而迁移是生产环境管理表结构变更的标准方式,二者混用会导致逻辑冲突。
可行解决方案
方案1:关闭migrationsRun,改用连接成功事件执行初始化逻辑
适合开发环境,保留synchronize自动建表,在应用启动完成后执行管理员账号插入:
- 修改TypeORM配置,关闭
migrationsRun:
return { type: "sqlite", database: "sqlite_db", synchronize: true, entities: [Account], // 移除或注释掉以下两行 // migrations: [MigrationOnStartup], // migrationsRun: true, migrationsTransactionMode: "each", logging: false, autoLoadEntities: true }
- 在应用启动代码中,监听TypeORM连接成功事件,执行初始化逻辑:
import { createConnection } from "typeorm"; import { Account } from "./entities/Account"; async function bootstrap() { const connection = await createConnection(); // 连接成功后检查并插入管理员账号 const accountRepo = connection.getRepository(Account); const adminAccount = await accountRepo.findOneBy({ email: "admin@admin" }); if (!adminAccount) { await accountRepo.insert({ email: "admin@admin", name: "admin", username: "admin" }); console.log("管理员账号已创建"); } // 启动你的应用(比如Express/NestJS) } bootstrap();
方案2:使用迁移完整管理表结构和数据插入(推荐生产环境)
完全依赖迁移机制,关闭synchronize,先创建建表迁移,再执行数据插入迁移:
- 修改TypeORM配置,关闭
synchronize,保留迁移相关配置:
return { type: "sqlite", database: "sqlite_db", synchronize: false, // 关闭自动同步 entities: [Account], migrations: [CreateAccountTableMigration, MigrationOnStartup], // 先建表,再插入数据 migrationsTransactionMode: "each", migrationsRun: true, logging: false, autoLoadEntities: true }
- 创建建表迁移(
CreateAccountTableMigration):
import { MigrationInterface, QueryRunner } from "typeorm"; import { Account } from "./entities/Account"; export class CreateAccountTableMigration implements MigrationInterface { async up(queryRunner: QueryRunner): Promise<void> { await queryRunner.createTable( queryRunner.connection.getMetadata(Account).table, true // 如果表不存在才创建 ); } async down(queryRunner: QueryRunner): Promise<void> { await queryRunner.dropTable("account"); } }
- 确保你的
MigrationOnStartup迁移在CreateAccountTableMigration之后执行(迁移文件名的时间戳或数组顺序决定执行顺序),原迁移代码可保留:
async up(queryRunner: QueryRunner): Promise<any> { const accountRepo = queryRunner.connection.getRepository(Account); const adminAccount = await accountRepo.findOneBy({ email: "admin@admin" }); if (!adminAccount) { await accountRepo.insert({ email: "admin@admin", name: "admin", username: "admin" }); } }
方案3:在现有迁移中手动检查表是否存在
如果暂时不想调整配置,可以在迁移代码中先检查表是否存在,不存在则创建:
async up(queryRunner: QueryRunner): Promise<any> { // 先检查account表是否存在,不存在则创建 const tableExists = await queryRunner.hasTable("account"); if (!tableExists) { await queryRunner.createTable( queryRunner.connection.getMetadata(Account).table, true ); } // 再执行插入逻辑 const accountRepo = queryRunner.connection.getRepository(Account); const adminAccount = await accountRepo.findOneBy({ email: "admin@admin" }); if (!adminAccount) { await accountRepo.insert({ email: "admin@admin", name: "admin", username: "admin" }); } }
内容的提问来源于stack exchange,提问作者great programmer
相关产品推荐
相关产品推荐

