在插入 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
值。
至于您的输入类型,您要允许传递 clickId
的 null
值吗?如果是这样,您还希望它在 ClickInput
中是 nullable: true
。例如,如果您 总是 在创建时需要 clickId
但后来 null
,那么您可以将其省略以要求输入 clickId
为非空。
我正在使用同时使用 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
值。
至于您的输入类型,您要允许传递 clickId
的 null
值吗?如果是这样,您还希望它在 ClickInput
中是 nullable: true
。例如,如果您 总是 在创建时需要 clickId
但后来 null
,那么您可以将其省略以要求输入 clickId
为非空。