在插入 TypeORM 和 TypeGraphQL 时,({nullable: true}) 选项去哪里了,有什么区别?

When insing TypeORM and TypeGraphQL, Where do the ({nullable: true}) options go and what's the difference?

我正在使用同时使用 TypeORM 和 Type-GraphQL 的服务器应用程序。

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

当我 运行 GraphQL 查询(使用 Apollo Studio)时,有时查询 returns 有一个空值错误,有时在添加新值时突变失败。

我测试了多种变体,但我得到的结果不一致会以奇怪的方式被拒绝。我调查了它,发现了从删除 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 => ID)
    @PrimaryGeneratedColumn("uuid")
    id: string;

    @Field(type => 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 Partial<Click> {

  //omitted the id field because it's generated on the server 
  
  @Field(type => ID)
  clickId: string; 

  @Field({ nullable: true })
  @MaxLength(256)  
  url: string; 

解析器

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 => Click)
export class ClickResolver {
  constructor(
    // constructor injection of a service
    private readonly clickService: ClickService, 
  ) {}   

  @Query( returns => [Click])
  async clicks() {    
    return this.clickService.list()
  }

  @Query( returns => Click, { nullable: true })  
  async click(@Arg("clickId") clickId: string) {
    return this.clickService.findById(clickId)
  }
  @Mutation( _type => Click )
  async createClick(@Arg("data") data: ClickInput): Promise<Click> {
    return this.clickService.create(data)
  }
  


 }

服务

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: Partial<Click>): Promise<Click> {
    const u = this.clickRepository.create(params);
    return this.update(u);
  }

  async update(Click: Click): Promise<Click> {
    return this.clickRepository.save(Click);
  }

  async delete(Click: Click): Promise<DeleteResult> {
    return this.clickRepository.delete(Click)
  }

  async list() {
    return this.clickRepository.find()
  }
}

如果您希望一个值为 null,则应将其同时放在两者上。

typeorm (@Entity) 中的

{ nullable: true } 表示允许数据库存储 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 值。


至于您的输入类型,您要允许传递 clickIdnull 值吗?如果是这样,您还希望它在 ClickInput 中是 nullable: true。例如,如果您 总是 在创建时需要 clickId 但后来 null ,那么您可以将其省略以要求输入 clickId 为非空。