处理空值
Input DTO用于数据录入,对于客户端提交的对象中的可空属性提供了强大行为控制能力,并将这种能力标准化。
数据录入中null相关的问题
回顾:直接保存实体对象
Jimmer实体最重要一个特征之一,就是严格区分数据未知 (不指定对象属性) 和没有数据 (将对象属性指定为null)。
让我们暂时将Input DTO的概念放到一旁,来回顾一下直接使用Jimmer实体保存数据时二者的差异。
-
将可空属性指定为null
- Java
- Kotlin
Book book = BookDraft.$.produce(draft -> {
draft.setId(12L);
draft.setName("TURING");
draft.setStoreId(null);
});
sqlClient.update(book);val book = Book {
id = 12L
name = "TURING"
storeId = null
}
sqlClient.update(book);生成如下SQL:
update BOOK
set
NAME = ?, /* TURING */
// highlight-next-line
STORE_ID = ? /* <null: long> */
where
ID = ? /* 12 */`可见,明确地将对象的属性设置为null,利用保存指令执行update操作,数据库中的值会被修改为null。
-
根本不指定可空属性
- Java
- Kotlin
Book book = BookDraft.$.produce(draft -> {
draft.setId(12L);
draft.setName("TURING");
// `storeId` is not specified
});
sqlClient.update(book);val book = Book {
id = 12L
name = "TURING"
// `storeId` is not specified
}
sqlClient.update(book);生成如下SQL:
update BOOK
set
NAME = ? /* TURING */
// highlight-next-line
/* `STORE_ID` is not updated */
where
ID = ? /* 12 */`可见,不设置对象的属性,利用保存指令执行update操作,数据库中的值不会被更改。
信息
这个区别非常重要。
在本文的后续内容中,我们不再讨论ORM生成了什么样的SQL语句,因为我们只需关注由Input DTO转换而得的实体对象属于哪种即可。
Input DTO面临的问题
现在,让我们来定义一个Input DTO:
input BookUpdateInput {
id!
name
id(store)
}
更多有关DTO语言的细节请参考相关章节,这里我们重点关注Jimmer预编译器根据这段DTO代码自动生成的Java/Kotlin代码。
生成代码如下
- Java
- Kotlin
BookUpdateInput.java
@GeneratedBy(file = "<your_project>/src/main/dto/Book.dto")
public class BookUpdateInput implements Input<Book> {
private long id;
private String name;
@Nullable
private Long storeId;
@Override
public Book toEntity() {
...略...
}
...省略其他成员...
}
BookUpdateInput.kt
@GeneratedBy(file = "<your_project>/src/main/dto/Book.dto")
data class BookUpdateInput(
val id: Long,
val name: String,
val storeId: Long? = null
) {
override fun toEntity(): Book = ...略...
...省略其他成员...
}
在原实体中,Book.store
关联属性允许为null。此处的DTO语言未对此做出改变,所以,在生成代码中,storeId
字段也允许为null。