Mutation
GraphQL Input介绍
在GraphQL中,查询返回的GraphQLObject,即任意形状的动态对象;然而,如果修改操作接受对象参数,必须是GraphQLInput,即固定形状的静态对象。
可参考GraphQLInput以了解更多。
以附带例子中的GraphQL声明文件为例schema.graphqls
type Book implements CommonEntity { ❶
id: Long!
name: String!
edition: Int!
price: BigDecimal!
store: BookStore
authors: [Author!]!
createdTime: LocalDateTime!
modifiedTime: LocalDateTime!
tenant: String!
}
input BookInput { ❷
id: Long
name: String!
edition: Int
price: BigDecimal!
storeId: Long
authorIds: [Long!]!
}
...省略其他代码...
-
❶
type
关键字声明的类型是表达任意形状数据结构的动态类型,用作GraphQL的输出类型 -
❷
input
关键字声明的类型是表达固定形状数据结构的静态类型,用作GraphQL的输入类型
定义Jimmer Input DTO
Jimmer的Input DTO在保存指令/InputDTO中有非常详细的介绍,本文不做赘述。
Jimmer提供了两种定义Input DTO的方式
采用DTO语言可以非常高效地达到我们的目标,所以本文采用这种方式。
-
在实体定义所在项目中,建立目录
src/main/dto
-
在
src/main/dto
下,按实体类型所处的包路径建立子目录com/yourcompany/yourproject/model
-
在上一步建立的目录下,建立文 件
Book.dto
,文件必须和实体类同名,扩展名必须为dto
-
编辑此文件,利用DTO语言,定义Book实体的各种DTO形状
Book.dtoinput BookInput {
#allScalars(Book)
id(store)
id(authors) as authorIds
}
...省略其他DTO定义...
编译完成后,将会自动生成如下Input DTO
- Java
- Kotlin
@GeneratedBy(file = "<your_project>/src/main/dto/Book.dto")
public class BookInput implements Input<Book> { ❶
@Nullable
private Long id;
private String name;
private int edition;
private BigDecimal price;
@Nullable
private Long storeId;
private List<Long> authorIds;
@Override
public Book toEntity() { ❷
...略...
}
...省略其他成员...
}
@GeneratedBy(file = "<your_project>/src/main/dto/Book.dto")
data class BookInput(
val id: Long? = null,
val name: String = "",
val edition: Int = 0,
val price: BigDecimal,
val storeId: Long? = null,
val authorIds: List<Long> = emptyList()
): Input<Book> { ❶
override fun toEntity(): Book = ❷
...略...
...省略其他成员...
}
-
❶
BookInput
类实现了接口org.babyfish.jimmer.Input
,该接口支持toEntity
方法,可以将当前Input DTO对象转化为Jimmer动态实体对象。 -
❷ 实现
Input.toEntity
方法
实现GraphQL mutation
- Java
- Kotlin
package com.example.business;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.MutationMapping;
import org.springframework.stereotype.Controller;
...省略其他导入...
@Controller
public class BookStoreService {
private final BookStoreRepository bookStoreRepository;
public BookStoreService(BookStoreRepository bookStoreRepository) {
this.bookStoreRepository = bookStoreRepository;
}
@MutationMapping ❶
@Transactional
public Book saveBook(
@Argument BookInput input ❷
) {
// `save(input)`是`save(input.toEntity())`的简写方式
return bookRepository.save(input); ❸
}
}
package com.example.business
import org.springframework.graphql.data.method.annotation.Argument
import org.springframework.graphql.data.method.annotation.MutationMapping
import org.springframework.stereotype.Controller
...省略其他导入...
@Controller
class BookStoreService(
private val bookStoreRepository: BookStoreRepository
) {
@MutationMapping ❶
@Transactional
fun saveBook(
@Argument input: BookInput ❷
): Book =
// `save(input)`是`save(input.toEntity())`的简写方式
bookRepository.save(input) ❸
}
-
❶ 使用注解
@org.springframework.graphql.data.method.annotation.MutationMapping
-
❷ 使用静态Input DTO类型
BookInput
,让用户只能传递规定形状的数据结构,以符合GraphQLInput的规范 -
❸ 保存指令,一句话保存任意形状的数据结构
这里的
bookRepository.save(input)
,其实是bookRepository.save(input.toEntity())
的简写。提示无论
BookInput
类型所定义数据结构简单还是相对复杂,都可以一句话保存。这是保存指令这个功能的核心价值。