Kotlin表连接特有功能
抉择
为了充分利用kotlin的语言优势充分优化其开发体验,Jimmer对Java和Kotlin提供不同的API,但二者本质相同。
然而,外连接却是唯一的例外,对于这个细节,Java API和Kotlin API的行为并不一样
-
Java DSL 采用JoinType表示连接类型,可以是
INNER(默认),LEFT,RIGHT或FULL -
Kotlin DSL
-
和实体属性同名的DSL属性表示内连接
-
相比于实体属性名后面多了一个
?的DSL属性表示左连接
即,Kotlin DSL不支持
RIGHT和FULL,这种牺牲是仔细权衡后的结果,目的为了换取在对Kotlin而言更重要的功能:把kotlin的null safety和SQL DSL完美结合。 -
初识DSL的null safety
实体BookStore的定义如下
@Entity
interface BookStore {
val name: String
val website: String?
...省略其他代码...
}
预编译器生成的代码如下
public val KNonNullProps<BookStore>.name: KNonNullPropExpression<String>
get() = get("name")
public val KNullableProps<BookStore>.name: KNullablePropExpression<String>
get() = get("name")
public val KProps<BookStore>.website: KNullablePropExpression<String>
get() = get("website")
请先忽略忽略这里生成的代码中各细节的具体作用,我们可以看到大量名称包含NoNull或Nullable的类型。
在Jimmer的Kotlin SQL DSL中,几乎所有AST类型都具备NoNull或Nullable两种实现。
这意味着,Kotlin SQL DSL具备和kotlin语言对等的的null safety特性,SQL风格的查询的代码具备完整的null safety自检能力。
让我们先看一个简单的例子
val tuples = sqlClient
.createQuery(BookStore::class) {
select(
table.name,
table.website ❶
)
}
.execute()
for ((name, website) in books) { ❷
println("Length of name: ${name.length}")
// 编译报错
println("Length of website: ${website.length}") ❸
}
-
由于
BookStore.website是可空的,❶处select的第二列的类型为String?而非String, 最终,查询返回的数据的类型为List<Tuple2<String, String?>> -
❷处通过循环遍历查询查询到的每一个元组,将其解构成变量
name和website。 由于tuples的类型为List<Tuple2<String, String?>>,这里website的类型是String? -
❸处对可能为null的
website进行.length运算,导致编译错误。
要修复这个编译错误,可以修改❸处的代码,将其中的.修改为?.
println("Length of website: ${website?.length}")