【问题标题】:NestJS/TypeORM. TypeORM doesn't update entity in DB, uses old cached entity insteadNestJS/TypeORM。 TypeORM 不更新数据库中的实体,而是使用旧的缓存实体
【发布时间】:2021-06-05 03:49:24
【问题描述】:

我整天都在尝试将实体保存到 MySQL 数据库中遇到巨大的困难。我正在使用 NestJS 和 TypeORM。

teacher.entity.ts

import { BeforeInsert, Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
import * as bcrypt from 'bcrypt';
import { bcryptConstants } from 'src/bcrypt/bcrypt.constants';

@Entity({'name': 'teacher'})

export class Teacher {

    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    username: string;

    @Column()
    email: string;

    @Column()
    password: string;

    @BeforeInsert()
    async hashPassword(): Promise<void> {
        const salt = await bcrypt.genSalt(bcryptConstants.saltRounds);
        const hash = await bcrypt.hash(this.password, salt);
        this.password = hash;
    }

}

app.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { SubjectsController } from './subjects/subjects.controller';
import { SubjectService } from './subjects/subject/subject.service'
import { TeacherModule } from './teacher/teacher.module';
import { AuthModule } from './auth/auth.module';

@Module({
  imports: [ TypeOrmModule.forRoot({
    type: 'mysql',
    host: 'localhost',
    port: 3306,
    username: 'root',
    password: 'root',
    database: 'test',
    entities: ["dist/**/*.entity{.ts,.js}"],
    synchronize: true,
    logging: true
  }), TeacherModule, AuthModule],
  controllers: [AppController, SubjectsController],
  providers: [AppService, SubjectService],
})
export class AppModule { }

这是错误:

+10767ms
query: START TRANSACTION
query: INSERT INTO `teacher`(`id`, `username`, `email`, `password`) VALUES (DEFAULT, ?, ?, ?) -- PARAMETERS: ["babbb","babbb","$2b$10$CMyzTJU6g1gJX2eO8Ulleez.LKo1XTCHvVKeUFKJS2FF9bwXivNR."]
query: COMMIT
+120008ms
query: START TRANSACTION
query: INSERT INTO `teacher`(`id`, `username`, `email`, `password`) VALUES (DEFAULT, ?, ?, ?) -- PARAMETERS: ["babbb","babbb","$2b$10$XU8QNxCRL4Ole2OxWkInruLogt0/e/SAfJoAhw.dBbad3MBb5D.iS"]
query failed: INSERT INTO `teacher`(`id`, `username`, `email`, `password`) VALUES (DEFAULT, ?, ?, ?) -- PARAMETERS: ["babbb","babbb","$2b$10$XU8QNxCRL4Ole2OxWkInruLogt0/e/SAfJoAhw.dBbad3MBb5D.iS"]

error: Error: Duplicate entry 'babbb' for key 'teacher.IDX_76fd0cda3fc6719d3109237c72'
{
  code: 'ER_DUP_ENTRY',
  errno: 1062,
  sqlState: '23000',
  sqlMessage: "Duplicate entry 'babbb' for key 'teacher.IDX_76fd0cda3fc6719d3109237c72'"
}
query: ROLLBACK
[Nest] 5360   - 03/06/2021, 9:59:03 PM   [ExceptionsHandler] Duplicate entry 'babbb' for key 'teacher.IDX_76fd0cda3fc6719d3109237c72' +192ms

实体实际上已保存在数据库中,但 NestJS 需要整整一分钟才能完成此任务并返回响应。我正在使用等待此响应的 Angular,以便在注册为教师后将用户重定向到登录页面。在发送发布请求以在数据库中创建教师后,我每分钟只收到状态 500 的错误。

mysql 表

id  username    email   password
1   user12  user    $2b$10$kYZ3F2Hv2MkuvQJIBUsK5Ogq4PHQPLiOBp1t9x3.psOwL984/KTQe
4   babbb   babbb   $2b$10$CMyzTJU6g1gJX2eO8Ulleez.LKo1XTCHvVKeUFKJS2FF9bwXivNR.

我已插入 2 个条目,但由于某种原因,它跳过了保存 ID 2 和 3。

我尝试使用“uuid”作为这样的 ID:

@PrimaryGeneratedColumn("uiid")
id: string;

但是当我明确将列定义为字符串时,它仍然给我一个错误,即生成的 uuid 字符串太长而无法保存为整数值。

欢迎提出任何建议!

更新

TypeORM 为我的列“用户名”和“电子邮件”添加了一个唯一索引,即使我没有在“@Column()”中指定它。

query: SELECT VERSION() AS `version`
query: SELECT * FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = 'test' AND `TABLE_NAME` = 'typeorm_metadata'
query: ALTER TABLE `teacher` CHANGE `username` `username` varchar(255) NOT NULL
query: ALTER TABLE `teacher` ADD UNIQUE INDEX `IDX_76fd0cda3fc6719d3109237c72` (`username`)
query: ALTER TABLE `teacher` CHANGE `email` `email` varchar(255) NOT NULL
query: ALTER TABLE `teacher` ADD UNIQUE INDEX `IDX_00634394dce7677d531749ed8e` (`email`)
query: COMMIT

即使我使用“@Column({ unique: false})”,它仍然会为它们添加唯一索引。我的其他表没有这个问题,只有这个。

第二次更新

好的,我肯定知道现在的问题是什么。 TypeORM 不能正确同步我的实体,更具体地说是“老师”实体。当我向“教师”表添加新列时,它会正确更新。当我从代码中删除“电子邮件”、“密码”、“用户名”列时,它们仍在表中,我无法更改这些列。我不知道这是否与某些缓存问题有关。我的同步“synchronize: true”已开启。

【问题讨论】:

    标签: mysql nestjs uuid typeorm


    【解决方案1】:

    您需要指定 @PrimaryGeneratedColumn 以生成 UUID 而不是 UIID 或您尝试的整数。

    # Not like this
    @PrimaryGeneratedColumn("uiid")
    id: string;
    
    # Like this
    @PrimaryGeneratedColumn("uuid")
    id: string;
    

    这是您的实体需要如何编写,指定 UUID 列类型。

    @Entity({ name: 'teacher' })
    export class Teacher {
        @PrimaryGeneratedColumn('uuid')
        id: string;
    
        @Column()
        username: string;
    
        @Column()
        email: string;
    
        @Column()
        password: string;
    
        @BeforeInsert()
        async hashPassword(): Promise<void> {
            const salt = await bcrypt.genSalt(bcryptConstants.saltRounds);
            const hash = await bcrypt.hash(this.password, salt);
            this.password = hash;
        }
    }
    

    关于保存时的延迟,Bcrypt 正在对您的密码进行哈希处理,通常需要很长时间。

    【讨论】:

    • 是的,我用“uiid”输入了错误的“uuid”,但我现在使用自动生成的数字作为我的 ID。当我没有在任何地方指定它们时,我发现问题与 TypeORM 使“用户名”和“电子邮件”等列唯一有关。因此,当我尝试使用相同的“用户名”或“电子邮件”发布实体时,它会引发重复错误。
    • 很高兴我解决了您的问题!关于您的问题,TypeORM 默认情况下不会使用 Column() 字段将任何字段设为主要或唯一字段,您需要在列选项中指定 unique: trueprimary: true
    【解决方案2】:

    您已经知道 NestJS 应该使用 TypeScript,然后为了让应用程序在 NodeJS 上运行,所有内容都被转换为 JavaScript 并保存在“dist”文件中,包括用 TypeScript 和 TypeORM 编写的实体。

    因为我多次更改了“教师”实体的列,后来我将 TypeORM 的选项更改为“同步:true”,所以 TypeORM 使用旧文件作为“dist”中的实体,而不是使用我写过的更新文件打字稿。

    因此,当您拥有 TypeORM 和“同步:true”时,TypeORM 将为您在数据库中创建表,但在我的情况下,它使用“dist”目录中的旧/缓存文件构建它们。

    如何解决

    在将 TypeORM 导入到您的模块时,尝试提供这些选项

    TypeOrmModule.forRoot({
         autoLoadEntities: true,
         synchronize: true,
         ...
    }
    

    删除您当前的 dist 文件夹,然后运行此命令 npm run build 以便它可以再次新建 dist 文件夹并可能删除旧文件。

    【讨论】:

    • 我建议你永远不要使用 TypeORM 的同步选项,在数据库更改时生成迁移以避免错误。
    【解决方案3】:

    清空你的 dist 文件夹

    rm -rf dist
    

    然后运行

    yarn build // or npm run build
    

    【讨论】:

      猜你喜欢
      • 2020-09-18
      • 2018-09-10
      • 2019-11-13
      • 2022-09-23
      • 2021-06-02
      • 2020-09-03
      • 1970-01-01
      • 2019-04-03
      • 1970-01-01
      相关资源
      最近更新 更多