DTO组合
DTO语言提供两种互补的组合机制:
| 机制 | 用途 | 是否生成类型 |
|---|---|---|
| 复用DTO | 将已有DTO用作关联属性的具体类型 | 是 |
| 片段 | 向当前DTO添加一组可复用属性 | 否 |
它们解决的问题不同。复用DTO会保留对象边界,而片段只向正在编译的DTO贡献属性。
复用DTO类型
通常,带有内联代码块的关联属性会生成一个嵌套DTO类型:
BookView {
store {
id
name
}
}
如果多个DTO需要相同的关联对象结构,可以只声明一次,然后在->之后引用它:
package com.example.api.dto
import com.example.model.*
StoreView for BookStore {
id
name
}
AuthorView for Author {
id
firstName
lastName
}
BookView for Book {
id
name
store -> StoreView
authors -> AuthorView
}
生成的BookView.store属性类型是StoreView,BookView.authors属性类型是
List<AuthorView>。Jimmer会复用被引用DTO的抓取器和转换元数据,而不会为这些属性
生成TargetOf_store或TargetOf_authors类。
复用DTO也可以和别名一起使用:
BookView for Book {
store as storeInfo -> StoreView
}
关联本身仍然决定生成的属性是单值还是列表。现有的?和!规则继续控制关联边界的
可空性。
输出和输入DTO
输出DTO中的关联必须引用兼容的输出View,输入DTO中的关联必须引用Input DTO:
input StoreInput for BookStore {
id
name
}
input BookInput for Book {
id
name
store -> StoreInput
}
关联目标实体和被引用DTO所表示的实体必须完全一致。例如,指向BookStore的关联不能
引用无关类型、基类型或子类型的DTO。输出View也不能作为可写的输入类型。
对于Input DTO,父关联保留自己的输入策略和存在性语义;被引用的Input DTO负责其 内部字段以及到不可变对象的转换。
Specification
Specification也支持相同的关联复用语法:
fragment AuthorFilters for Author {
like/i(firstName, lastName) as name
}
specification StoreSpecification for BookStore {
ge(name)
le(name)
}
specification AuthorSpecification for Author {
#include(AuthorFilters)
}
specification BookSpecification for Book {
like/i(name)
store -> StoreSpecification
authors -> AuthorSpecification
}
生成的BookSpecification会直接使用StoreSpecification和
AuthorSpecification,而不会生成TargetOf_store和TargetOf_authors。
单值和列表关联都 使用一个嵌套Specification对象:关联基数决定如何应用其中的谓词,
而不改变生成的属性类型。现有查询语义保持不变,例如单值关联使用join,列表关联使用
exists谓词。
被引用的Specification必须表示关联的准确目标类型。它可以使用显式的for目标,也可以
来自已编译的依赖。片段仍然不绑定DTO种类,因此可以导出like、ge和le等函数;
这些声明会在片段被Specification包含时按Specification规则校验。
关联配置
被引用DTO定义关联对象的结构,而抓取配置仍属于使用它的关联:
BookView for Book {
!fetchType(JOIN_ALWAYS)
store -> StoreView
!batch(32)
!orderBy(lastName asc, firstName asc)
authors -> AuthorView
}
!fetchType、!batch、!where和!orderBy等配置不会被复制到StoreView或
AuthorView中。
多态和模块边界
通过#types生成的多态View或Input DTO,可以通过其生成的根DTO类型被复用。分支选择、
抓取和转换仍由该DTO的生成元数据处理,单值关联和列表关联都支持这种用法。
可复用DTO也可以来自已编译的依赖模块,像普通类型一样导入生成的DTO即可。其公开的
View<T>或Input<T>契约以及生成元数据足以支持复用。
直接或间接的DTO复用环会导致元数据循环初始化,因此会在编译期被拒绝。递归对象图 应继续使用DTO语言已有的显式递归关联功能。
片段
片段是一个在源码层面命名的DTO属性集合:
fragment BookSummaryFields for Book {
id
name
edition
}
BookSummaryView for Book {
#include(BookSummaryFields)
}
BookDetailView for Book {
#include(BookSummaryFields)
price
store -> StoreView
}