При использовании TypeORM и TypeGraphQL, куда идут параметры ({nullable: true}) и в чем разница?

#typeorm #typegraphql

Вопрос:

Я работаю с серверным приложением, которое использует как TypeORM, так и Type-GraphQL.

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

Когда я запускаю запросы GraphQL (используя Apollo Studio), иногда запрос возвращает ошибку из-за наличия нулевых значений, а в других случаях мутация завершается неудачно при добавлении нового значения.

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

В чем разница между введением { nullable: true } @field() или @column() и тем, что не должно просто работать ? в определении типа?

Я также разделил свои @InputType() @Entity() классы и на отдельные файлы, поэтому нужно ли мне также использовать одни и те же значения @field() во входных данных?

Полный пример:

Сущность

 import { Field, ID, ObjectType } from "type-graphql"; import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm";  @Entity() @ObjectType() export class Click extends BaseEntity{    @Field(type =gt; ID)  @PrimaryGeneratedColumn("uuid")  id: string;   @Field(type =gt; ID)  @Column({ nullable: true })  clickId?: string;    @Field({ nullable: true })  @Column({ nullable: true })  url?: string;  }  

Ввод

 import { MaxLength } from "class-validator"; import { Field, ID, InputType } from "type-graphql"; import { Click } from '../entity/Click';  @InputType() export class ClickInput implements Partiallt;Clickgt; {   //omitted the id field because it's generated on the server     @Field(type =gt; ID)  clickId: string;    @Field({ nullable: true })  @MaxLength(256)   url: string;   

Resolver

 import {  Arg, Mutation,  Query,  Resolver } from "type-graphql"; import { Service } from "typedi"; import { Click } from "../entity/Click"; import { ClickInput } from "../input/ClickInput"; import { ClickService } from "../service/ClickService";  @Service()  @Resolver(of =gt; Click) export class ClickResolver {  constructor(  // constructor injection of a service  private readonly clickService: ClickService,   ) {}    @Query( returns =gt; [Click])  async clicks() {   return this.clickService.list()  }   @Query( returns =gt; Click, { nullable: true })   async click(@Arg("clickId") clickId: string) {  return this.clickService.findById(clickId)  }  @Mutation( _type =gt; Click )  async createClick(@Arg("data") data: ClickInput): Promiselt;Clickgt; {  return this.clickService.create(data)  }      }  

Service

 import { Service } from "typedi"; import { DeleteResult } from "typeorm"; import { InjectRepository } from "typeorm-typedi-extensions"; import { Click } from "../entity/Click"; import { ClickRepository } from "../repo/ClickRepo";   @Service() export class ClickService {  constructor(  @InjectRepository(Click)  private readonly clickRepository: ClickRepository  ) {}    async findById(clickId: string, relations: string[] = []) {  return this.clickRepository.findOne({  where: {  clickId,  },  relations: relations,  });  }   async create(params: Partiallt;Clickgt;): Promiselt;Clickgt; {  const u = this.clickRepository.create(params);  return this.update(u);  }   async update(Click: Click): Promiselt;Clickgt; {  return this.clickRepository.save(Click);  }   async delete(Click: Click): Promiselt;DeleteResultgt; {  return this.clickRepository.delete(Click)  }   async list() {  return this.clickRepository.find()  } }  

Ответ №1:

Если вы хотите, чтобы значение было нулевым, вы должны поместить его в оба.

{ nullable: true } в typeorm ( @Entity ) означает, что базе данных разрешено хранить null значения. В противном случае вы даже не сможете сохранить объект, не определив этот столбец.

{ nullable: true} in type-graphql ( @Field ) означает, что схема, созданная с помощью TypeGraphQL , позволит этому полю быть null . В противном случае при запросе вы могли бы ожидать, что потенциально получите ошибку Cannot return null for non-nullable field EntityName.fieldName .


Чтобы уточнить, схема GraphQL может выглядеть следующим образом:

 type Click {  id: ID!  clickId: ID!  url: String }  

Обратите внимание, как url нет ! , так что это не обязательно, но clickId есть, так что вы столкнетесь с проблемами, если передадите null значение.


Что касается вашего типа ввода, хотите ли вы разрешить null передачу значения для clickId ? Если это так, вы также хотели бы, чтобы он был nullable: true внутри ClickInput . Если, например, вы всегда требовали a clickId при создании, но сделали это null позже, то вы можете оставить это, чтобы требовать, чтобы входные clickId данные были ненулевыми.

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

1. Я и сам не смог бы объяснить это лучше. Отличный ответ!