Как мне правильно обновить отношения сущностей в Typeorm

#javascript #typescript #lazy-loading #typeorm

#javascript #typescript #отложенная загрузка #typeorm

Вопрос:

У меня есть базовая таблица пользователей, в которой они могут владеть различными музыкальными инструментами. У меня возникли проблемы с поиском правильного способа создания базовой updateUser функции, с помощью которой они могут обновлять свою пользовательскую информацию, а также свои навыки работы с инструментами, используя Typeorm и базу данных MySQL.

Класс пользователя

 @Entity()
@ObjectType()
export class User extends BaseEntity {

  public constructor(init?:Partial<User>) {
      super();
      Object.assign(this, init);
  }

  @Index({ unique: true})
  @Column()
  email: string;

  @Index({ unique: true})
  @Column()
  username: string;

  @Column()
  @HideField()
  password: string;

  @Column({
      nullable: true
  })
  profilePicture?: string;

  @Index({ unique: true})
  @Column()
  phoneNumber: string;

  //Lazy loading
  @OneToMany(() => UserInstrument, p => p.user, {
      cascade: true
  })
  instruments?: Promise<UserInstrument[]>;
}
 

Класс пользовательского инструмента

 @Entity()
@ObjectType()
export class UserInstrument extends BaseEntity {

  public constructor(init?:Partial<UserInstrument | InstrumentProficiencyInput>) {
      super();
      Object.assign(this, init);
  }

  @Column({
      type: 'enum',
      enum: Instrument
  })
  instrument : Instrument

  @Column()
  proficiency : number;

  @JoinColumn()
  @HideField()
  userId : number;

  @ManyToOne(() => User, p => p.instruments)
  @HideField()
  user : User;
}
 

Теперь создание нового пользователя с помощью предопределенных инструментов не было проблемой. Я могу просто вставить нового пользователя, и он автоматически заполнит поля Id и UserId для соответствующих таблиц.

   async create(request: RegisterUserInput) : Promise<boolean>{
    const user        = new User();
    user.username     = request.username;
    user.password     = request.password;
    user.phoneNumber  = request.phoneNumber;
    user.email        = request.email;
    user.instruments  = Promise.resolve(request.instruments?.map(p => new UserInstrument(p)));

    const result = await this.usersRepository.save(user);
}
 

Проблема

Теперь всякий раз, когда я делаю что-то подобное для обновления таблиц User / Instrument, я получаю "ER_BAD_NULL_ERROR: Column 'userId' cannot be null" исключение

   async updateUser(request: UpdateUserInput, id : number): Promise<boolean> {
    var user = new User(classToPlain(request));
    user.id = id;
    user.instruments = Promise.resolve(request.instruments?.map(p => new UserInstrument(p)));

    (await user.instruments)?.forEach(p => p.userId = id);

    await this.usersRepository.save(user);

    return true;
}
 

Этот код генерирует следующее исключение

 code:'ER_BAD_NULL_ERROR'
errno:1048
index:0
message:'ER_BAD_NULL_ERROR: Column 'userId' cannot be null'
name:'QueryFailedError'
parameters:(2) [null, 8]
query:'UPDATE `user_instrument` SET `userId` = ? WHERE `id` = ?'
sql:'UPDATE `user_instrument` SET `userId` = NULL WHERE `id` = 8'
sqlMessage:'Column 'userId' cannot be null'
sqlState:'23000'
stack:'QueryFailedError: ER_BAD_NULL_ERROR: Column 'userId' cannot be null
 

Хотя, когда я проверяю свой пользовательский объект, я вижу userId , что поле установлено правильно

 __has_instruments__:true
__instruments__:(1) [UserInstrument]
    0:UserInstrument {created: '2020-11-29 02:46:10', instrument: 'Guitar', proficiency: 5, userId: 30}
length:1
 

Итак, что я делаю не так? Существует ли более предпочтительный способ обновления таблицы инструментов пользователей без прямого доступа к репозиторию инструментов? Я не уверен, почему работает начальный вариант save моего метода create, но не при обновлении.

Комментарии:

1. Прежде всего, в нем нет SQL-кода, пожалуйста, удалите тег MySQL…..