#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. Я и сам не смог бы объяснить это лучше. Отличный ответ!