TypeORM AfterSave() 在创建后触发,但查询时返回 NULL [英] TypeORM AfterSave() triggers after creation but when queried, it returns NULL

查看:32
本文介绍了TypeORM AfterSave() 在创建后触发,但查询时返回 NULL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为 Trip 的实体.结构是:

我想要的是每当创建新行程时,room 列应填充 ${tripId}_${someRandomStringHere}.例如,我刚刚使用这个 body 创建了一个新的行程:

响应应该是:

新创建的tripid15.因此,响应的 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 资源:

我的问题是:

  1. 为什么每当我使用该方法methodsubscriber时,它都不起作用.这不是正确的做法吗?为什么在文档中?或者用于其他用例?
  2. 我真的必须使用订阅者才能实现吗?这么多步骤.

我来自 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:

  1. 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?
  2. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆