TypeORM AfterSave () срабатывает после создания, но при запросе возвращает NULL - PullRequest
1 голос
/ 06 июня 2019

У меня есть сущность с именем Trip.Структура: db structure

Что мне нужно, чтобы при создании новой поездки столбец room заполнялся ${tripId}_${someRandomStringHere}.Так, например, я только что создал новую поездку, используя это тело:

trip_body

Ответ должен быть: tr]ip response

Вновь созданный trip имеет id из 15.Таким образом, ответ имеет значение room, оцененное в 15_4gupvdo0ea408c25ia0qsbh, потому что снова: ${tripId}_${someRandomStringHere}.

. Это работает как ожидаемый всякий раз, когда я POST запрашиваю и создаю поездку. НО всякий раз, когда я запрашиваю все созданные поездки, свойство room каждого объекта поездки показывает null!

Look at the /api/trips:

trips array

room свойство NULL .Так что, черт возьми, я не понимаю, что происходит.

Мой 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
  }

Я недумаю, что мне нужно включить код Trip Controller, но в любом случае .. Я не знаю, почему это происходит, потому что у меня есть пользовательский объект с @BeforeUpdate и работает нормально ...

После прочтения многоподобных проблем с github, смотрел уроки на youtube [Привет, Бен Авад!: D], я нашел несколько исправлений .. с помощью подписчиков

На самом деле, я не знаю, в чем отличие слушателя / подписчика.Возможно я делаю неправильное использование.Может кто-нибудь просветить меня, пожалуйста?Например, отличие AfterSave от Entity Listener от AfterSave от Entity Subscriber.Когда / Лучший вариант для использования?что-то вроде того.В любом случае вернемся с "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, но я не знаю, как обновить его без необходимости запрашивать и обновлять его с помощью event.manager.getRepository().Пожалуйста, кто-нибудь может исправить этот код для меня?правильный способ сделать это?

СЕЙЧАС, это работает! тело запроса: the request body

/ api / trips res: res

Мои вопросы:

  1. Почему всякий раз, когда я использую этот метод для подписчика, он не работает.Разве это не правильный способ сделать это?Почему это в документах?Или для другого варианта использования?
  2. Должен ли я действительно использовать подписчика для этого?Вот так много шагов.

Я пришел из Rails.Поэтому создавать файлы / подписчики просто утомительно.В отличие от after_save обратного вызова ActiveRecord, это очень просто ..

PS.Я новичок в nest-js и typeorm

Ответы [ 2 ]

1 голос
/ 06 июня 2019

Похоже, что происходит с вашим AfterInsert, так это то, что вы просто создаете случайную строку комнаты, но не сохраняете значение в базу данных, а только используете возвращение идентификатора, чтобы вы могли создатьстрока.Что вы могли бы сделать в вашем AfterInsert - это запустить функцию save() из EntityManager или RepositoryManger еще раз и зафиксировать значение в базе данных, аналогично тому, что вы делаете в себе Subscriber.Я не слишком углубился в декораторы Subscriber / Listener против Before-/AfterInsert, поэтому не могу дать более глубокий ответ на ваши вопросы.

Если вы не хотите делать два коммитав базу данных вы всегда можете сделать запрос для самого последнего идентификатора и увеличить его на 1 (таким образом, сопоставляя то, что новый идентификатор объекта должен быть) с чем-то вроде

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)

Это немного неуклюже, чтобы посмотреть, но это не требует двух записей в базу данных (хотя вам обязательно нужно убедиться, что после создания комнаты и поездки имеют одинаковый идентификатор).

Ваш последний вариант будетсоздать в вашей базе данных триггер, который выполняет те же функции, что и код JavaScript.

0 голосов
/ 06 июня 2019

@AfterInsert метод просто изменит ваш объект JS после завершения вставки в БД.Так вот почему ваш код не работает.Вы должны использовать @BeforeInsert декоратор.BeforeInsert изменит вашу сущность / объект JS перед вставкой / сохранением в БД.

...