TypeORM AfterSave()创建后触发,但在查询时返回NULL

时间:2019-06-06 17:36:09

标签: javascript typescript nestjs typeorm

我有一个名为Trip的实体。结构为: db structure

我想要的是无论何时创建新的旅程,都应在room列中填充${tripId}_${someRandomStringHere}。因此,例如,我刚刚使用此主体创建了一个新行程:

trip_body

响应应为: tr]ip response

新创建的trip的{​​{1}}中的id。因此,响应中的15的值为room,因为同样:15_4gupvdo0ea408c25ia0qsbh

每当我${tripId}_${someRandomStringHere}请求并创建行程时,此操作就会按预期的方式工作。 但是,每当我查询所有创建的行程时,每个行程对象的POST属性都会显示room

null

trips array

Look at the /api/trips:属性为 NULL 。所以我到底不知道发生了什么事。

我的room代码是:

Trip Entity

我的import { PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, Entity, Unique, ManyToOne, AfterInsert, JoinColumn, getConnection } from 'typeorm' import { DriverEntity } from 'src/driver/driver.entity'; @Entity('trips') export class TripEntity { @PrimaryGeneratedColumn() id: number @Column() destination: string @Column('decimal') destination_lat: number @Column('decimal') destination_long: number @Column() maxPassenger: number @Column() totalPassenger: number @Column({ nullable: true }) room: string @CreateDateColumn() created_at: Date @UpdateDateColumn() updated_at: Date // --------->HERE: The after insert @AfterInsert() async createSocketRoom(): Promise<void> { const randomString = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) this.room = `${this.id}_${randomString}` } // Trip belongs to driver // Adds driver_id to trips table @ManyToOne(type => DriverEntity, driver => driver.trips) @JoinColumn({ name: 'driver_id' }) driver: DriverEntity } 是:

Trip Service Code

我认为我不需要包含async create(data: CreateTripDTO) { const { driver_id } = data const driver = await this.driverRepository.findOne({ where: { id: driver_id } }) const trip = await this.tripRepository.create(data) trip.driver = driver await this.tripRepository.save(trip) return trip } 代码,但无论如何.. 我不知道为什么会这样,因为我的用户实体带有@BeforeUpdate并且可以正常工作...

在阅读了许多类似的github问题之后,观看了youtube教程[嗨,本·阿瓦德! :D],通过使用订阅服务器

,我发现了一个解决方法。

实际上,我不知道侦听器/订阅者有什么区别。也许我做错了用法。有人可以启发我吗?例如,实体侦听器的AfterSave与实体订阅者的AfterSave的区别。什么时候/最好用?这样的事情。无论如何都回到Trip Controller

我创建了一个"fix..."

Trip Subscriber

起初它不起作用,但是经过数小时的挖掘之后,我需要在import { EventSubscriber, EntitySubscriberInterface, InsertEvent } from "typeorm"; import { TripEntity } from "src/trip/trip.entity"; @EventSubscriber() export class TripSubsriber implements EntitySubscriberInterface<TripEntity> { // Denotes that this subscriber only listens to Trip Entity listenTo() { return TripEntity } // Called after entity insertion async afterInsert(event: InsertEvent<any>) { console.log(`AFTER ENTITY INSERTED: `, event.entity); const randomString = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) // query the trip with given event.entity const trip = await event.manager.getRepository(TripEntity).findOne(event.entity.id) // populate the room with desired format trip.room = `${trip.id}_${randomString}` // save it! await event.manager.getRepository(TripEntity).save(trip) } } 上添加一个具有我的订阅者路径值的subscriber属性,它才能起作用! 例如:ormconfig.json

同样,"subscribers": [ "src/subscriber/*.ts" ]代码对我来说似乎是意大利面条,因为我已经有了Trip Subscriber对象,但是我不知道如何更新它而不需要使用event.entity查询和更新它。请有人可以为我修复此代码吗?正确的方法呢?

现在,它正在工作! 请求正文: the request body

/ api / trips res: res

我的问题是:

  1. 为什么每当我使用该方法methoud订户时,它都无法正常工作。这不是正确的方法吗?为什么在文档中?还是其他用例?
  2. 我真的必须使用订阅服务器来实现吗?多数步骤如此。

我来自Rails。因此,必须创建文件/订户才能使其有些累。与ActiveRecord的event.manager.getRepository()回调不同,它非常简单。

PS。我是Nest-js和Typeorm的新手

3 个答案:

答案 0 :(得分:1)

您的AfterInsert所发生的情况是您正在创建随机房间字符串就很好了,但是您没有将值保存到数据库中,仅使用了ID的返回值,以便您可以创建字符串。您可以在AfterInsert中执行的操作再次从save()EntityManager运行RepositoryManger函数,并将值提交给数据库,类似于您在数据库中发生的情况您Subscriber。我还没有深入研究Subscriber / ListenerBefore-/AfterInsert装饰器,因此无法对您的问题给出更深层次的答案。

如果您不想对数据库进行两次提交,则始终可以查询最新的id并将其递增1(因此,与新对象id 匹配) ),例如

const maxId = await this.tripRepository.findOne({select: ['id'], order: {id: "DESC"} });
const trip = await this.tripRepository.create(data);
const randomString = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
this.room =  `${maxId + 1}_${randomString}`
trip.driver = driver
await this.tripRepository.save(trip)

看起来有点笨拙,但是不需要两次写入数据库(尽管您肯定需要确保创建后的房间和旅程具有相同的ID)。

您最后的选择是在数据库中创建一个与JavaScript代码相同的触发器。

答案 1 :(得分:0)

@AfterInsert方法仅会在插入数据库后修改您的JS对象。因此,这就是为什么您的代码无法正常工作的原因。您必须使用@BeforeInsert装饰器。 BeforeInsert将在插入/保存到数据库之前修改您的JS实体/对象。

答案 2 :(得分:0)

您只需要在createSocketRoom()函数中使用“ this.save()”

https://i.stack.imgur.com/oUY8n.png使用后的查询!!