TypeORM AfterSave() 在创建后触发,但查询时返回 NULL [英] TypeORM AfterSave() triggers after creation but when queried, it returns NULL
问题描述
我有一个名为 Trip
的实体.结构是:
我想要的是每当创建新行程时,room
列应填充 ${tripId}_${someRandomStringHere}
.例如,我刚刚使用这个 body 创建了一个新的行程:
响应应该是:
新创建的trip
的id
为15
.因此,响应的 room
值为 15_4gupvdo0ea408c25ia0qsbh
,因为再次:${tripId}_${someRandomStringHere}
.
每当我POST
请求并创建行程时,这都会按预期工作.但是每当我查询创建的所有行程时,每个行程对象的 room
属性都会显示 null
!
看/api/trips:
room
属性为 NULL.所以到底发生了什么,我不明白发生了什么.
我的旅行实体
代码是:
import { PrimaryGeneratedColumn, Column, CreateDateColumn,UpdateDateColumn、Entity、Unique、ManyToOne、AfterInsert、JoinColumn、getConnection } 来自 'typeorm'从'src/driver/driver.entity'导入{DriverEntity};@Entity('旅行')导出类 TripEntity {@PrimaryGeneratedColumn()身份证号码@柱子()目的地:字符串@Column('十进制')目的地纬度:数字@Column('十进制')destination_long:数字@柱子()最大乘客:数量@柱子()总乘客数:数量@Column({ nullable: true })房间:字符串@CreateDateColumn()created_at: 日期@UpdateDateColumn()更新时间:日期//--------->HERE: 后插入@AfterInsert()异步 createSocketRoom(): Promise{const randomString = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)this.room = `${this.id}_${randomString}`}//行程属于司机//将 driver_id 添加到行程表@ManyToOne(type => DriverEntity, driver => driver.trips)@JoinColumn({ 名称:'driver_id' })驱动程序:DriverEntity}
我的旅行服务代码
是:
async create(data: CreateTripDTO) {const { driver_id } = 数据const driver = await this.driverRepository.findOne({ where: { id: driver_id } })const trip = await this.tripRepository.create(data)trip.driver = 司机等待 this.tripRepository.save(trip)回程}
我认为我不需要包含 Trip Controller
代码,但无论如何..我不知道为什么会这样,因为我的用户实体带有 @BeforeUpdate 并且工作正常......
在阅读了很多类似的 github 问题后,观看了 youtube 教程 [Hi Ben Awad!:D],我找到了一些解决方法..通过使用订阅者
其实我也不知道 Listener/Subscriber 有什么区别.也许我做错了用法.有人可以启发我吗?例如实体侦听器的 AfterSave 与实体订阅者的 AfterSave 的区别.何时/最佳使用情况?类似的东西.无论如何回到 "fix..."
我创建了一个Trip Subscriber
:
import { EventSubscriber, EntitySubscriberInterface, InsertEvent } from "typeorm";从src/trip/trip.entity"导入{TripEntity};@EventSubscriber()导出类 TripSubsriber 实现了 EntitySubscriberInterface<TripEntity>{//表示这个订阅者只监听 Trip Entity听(){返回 TripEntity}//实体插入后调用异步 afterInsert(事件:InsertEvent/api/trips 资源:
我的问题是:
- 为什么每当我使用该方法methodsubscriber时,它都不起作用.这不是正确的做法吗?为什么在文档中?或者用于其他用例?
- 我真的必须使用订阅者才能实现吗?这么多步骤.
我来自 Rails.所以不得不创建文件/订阅者只是为了做这有点累.与 ActiveRecord 的 after_save
回调不同,它非常简单..
附注.我是 nest-js 和 typeorm 的新手
解决方案 @AfterInsert
方法只会在插入数据库后修改你的 JS 对象.这就是为什么您的代码不起作用的原因.您必须使用 @BeforeInsert
装饰器.BeforeInsert
将在插入/保存到数据库之前修改您的 JS 实体/对象.
I have an Entity called Trip
. The structure is:
What I want is whenever a new trip is created, the room
column should be populated with ${tripId}_${someRandomStringHere}
. So for example, I just created a new trip using this body:
The response should be:
The newly created trip
has the id
of 15
. So, the response has the room
valued at 15_4gupvdo0ea408c25ia0qsbh
because again: ${tripId}_${someRandomStringHere}
.
This is working as expected whenever I POST
the request and create the trip. BUT whenever I query all the trips created, the room
property of each trip objects shows null
!
Look at the /api/trips:
room
property is NULL. So what the heck I dont understand what is happening.
My Trip Entity
code is:
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
}
My Trip Service Code
is:
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
}
I dont think I need to include the Trip Controller
code but anyway..
I don't know why it is happening because I have my User Entity with @BeforeUpdate and works fine...
After reading alot of similar github issues, watched youtube tutorials [Hi Ben Awad! :D], I found a somewhat fix.. by using Subscribers
Actually, I don't know what is the difference of the Listener/Subscriber. Maybe I am doing the wrong usage. Can someone enlighten me please? For example the difference of AfterSave of Entity Listener vs AfterSave of Entity Subscriber. When/Best case to use? something like that. Anyway back with the "fix..."
I created a 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)
}
}
At first it is not working but after digging for hours again, I need to add a subscriber
property with the value of the path of my subscribers at the ormconfig.json
for it to work!
e.g: "subscribers": [
"src/subscriber/*.ts"
]
Again, the Trip Subscriber
code seems spaghetti to me because I already have the event.entity
object but I do not know how to update it without the need of querying and updating it using event.manager.getRepository()
. Please can someone fix this code for me? the proper way of doing it?
NOW, It is working!
the request body:
the /api/trips res:
My questions are:
- Why whenever I use that method methoud subscriber, it is not working. Is it not the proper way to do it? The why is it in the docs? Or for other use case?
- Do I really have to use subscriber for it to achieve? Thats so many steps.
I came from Rails. So having to create files/subscribers just to do it somewhat tiring. Unlike ActiveRecord's after_save
callback it is very easy..
PS. I'm new to nest-js and typeorm
解决方案 @AfterInsert
method will just modify your JS object after inserting into DB is done. So thats reason why is your code not working. You have to use @BeforeInsert
decorator. BeforeInsert
will modify your JS entity/object before inserting/saving into DB.
这篇关于TypeORM AfterSave() 在创建后触发,但查询时返回 NULL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!