当前位置: 首页 > 知识库问答 >
问题:

NestJS/TypeORM.TypeORM不会更新DB中的实体,而是使用旧的缓存实体

曾丰茂
2023-03-14

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

教师实体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,它等待这个响应,以便在注册为教师后将用户重定向到登录页面。在发送post请求在数据库中创建教师后,我仅在一分钟内收到状态为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为我的列“username”和“email”添加了一个唯一的索引,即使我没有在“@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无法正确同步我的实体,更确切地说是“教师”实体。当我向“教师”表添加新列时,它会正确更新。当我从代码中删除“email”、“password”、“username”列时,它们仍然在表中,我无法更改这些列。我不知道这是否与缓存问题有关。我的同步“synchronize:true”处于启用状态。

共有2个答案

郎仰岳
2023-03-14

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

因为我多次更改了我的“老师”实体的列,并且我后来将TypeORM的选项更改为“同步:真实”,TypeORM使用“dist”中的旧文件作为实体,而不是使用我在TypeScript中编写的更新文件。

因此,当您使用TypeORM和“synchronize:true”时,TypeORM将在数据库中为您创建表,但在我的例子中,它使用的是来自“dist”目录的旧/缓存文件。

如何修复它

在将其导入模块时,尝试提供这些选项以进行打字

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

删除当前的dist文件夹,然后运行此命令npm run build,这样它就可以重新创建dist文件夹,并可能删除旧文件。

常英纵
2023-03-14

您需要指定到@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正在散列您的密码,通常需要很长时间。

 类似资料:
  • 我已经为创建新表和更新后端的TypeORM实体苦苦挣扎了一周。我们将NestJS、GraphQL和TypeORM与PSQL数据库一起使用。我们有一个生产服务器/数据库设置,客户信息已经保存。我正在尝试使用代码优先的方法向数据库中添加一个新表来生成模式。在repo的主分支上,我在本地环境中启动它,并连接到一个干净的数据库。创建帐户并将信息保存到表后,我将切换到一个新分支,该分支包含用于实现新表的代码

  • 我有一个实体像下面在Nestjs应用程序与typeorm为mongoDB: 我的其他实体扩展了审计,在我的应用程序中,我使用jwt来验证用户。 问题是,当我想保存一个实体,我不知道如何设置createdBy与@Before插入钩子... 我知道请求中有用户,但我不知道将用户引入方法的正确方法是什么?

  • 背景: < li >我正在使用< code>npm和< code>docker在< code>node.js中编写代码。我试图让我的docker文件在构建时使用缓存,这样不会花太长时间。 < li >我们有一个“通用”存储库,用于保存在各种存储库中使用的逻辑,并通过npm软件包进行传播。 问题是: 我希望docker文件不要使用我的“通用”包上的缓存。 Docker文件: package.json

  • 我使用spring数据和hibernate。我有一个实体(TestEntity)。我创建了一个自定义hibernate类型,将一个字符串字段反序列化为两列。如果我持久化一个实体,然后对其进行更改,则一切正常,hibernate会发送更新查询(它使我的类型正常工作,而对DB的更新查询会将我的旧列“拆分”为两个新列)。但我的目标是让这项记录成为移民之王。我不能使用普通的DB迁移,因为我的自定义类型中有

  • 我在我的GAE数据存储实验中发现了一些很奇怪的东西。我使用的是GAE SDK 1.7.5。我不确定我的发现是否正确。 基本上,我发现在执行数据存储get之前,将实体放入数据存储并进行计数不会返回正确的值。 如果你想更深入地挖掘,这里是我前面的SO问题中的实际代码:

  • 我在代码优先的情况下使用EF,我有这样的模型: 我收到一个客户ID和一个产品ID列表。当产品在数据库中不存在时,我想添加它: 问题是EF试图级联更改并尝试插入一个新的对象,其ID与现有对象相同,因此失败。我如何解决这个问题? 这是插入方法: