脱钩操作
在采用关联模式AssociatedSaveMode.REPLACE保存关联对象时,会涉及一个重要的概念:脱勾操作。
概念
| 数据库已有数据结构 | 用户期望保存的数据结构 |
|---|---|
| |
-
对于
Bread而言,在新旧数据结构中都存在,对应update操作 -
对于
Drinks而言,在旧数据结构中不存在,但在新数据中存在,对应INSERT操作 -
对于
Meat而言,在旧数据结构中存在,但在新数据中不存在,对应的操作叫做脱勾操作。
脱勾针对两种关联
-
中间表关联
所谓中间表的关联,显然,指的就是本教程中
Book.authors和Author.books这类关联。其脱钩操作非常简单,只是简单地删除中间表的关联而已,关联对象本身不受任何影响。
-
子表关联
所谓子表关联,指基于外键 (无论真伪) 关联的逆关联,例如本教程中的
BookStore.books。其脱钩操作非常简单相对复杂。开发人员可以通过配置来控制具体脱钩行为。
接下来,我们讨论这两种脱勾操作。
脱勾中间表关联
在介绍关联对象的REPLACE保存模式时,我们已经展示了这种最简单的脱钩行为。
因此,本文不再赘述。
脱勾子表关联
所谓子表关联,指基于外键 (无论真伪) 关联的逆向关联,例如BookStore.books。
其脱钩操作非常简单相对复杂。开发人员可以为外键所对应的属性 (例如这里的Book.store) 配置脱钩模式,来实现不同的脱钩行为。
脱勾模式
子对象脱勾操作有5种模式
| 模式 | 描述 |
|---|---|
NONE (默认) | 视全局配置jimmer.default-dissociate-action-checking而定
|
| LAX | 脱钩操作不执行任何动作。
|
| CHECK | 不支持脱钩操作,如果数据库中当前父对象拥有需要脱钩的子对象,则抛出异常阻止操作。 |
| SET_NULL | 把被脱勾的子对象的外键设置为null。使用此模式的前提是子对象的外键关联属性是nullnullable的;否则尝试此配置将会导致异常。 |
| DELETE | 将被脱勾的子对象删除。 |
配置脱勾模式有两种方法
-
在实体上用注解静态配置,静态配置是全局的。
-
在代码中代码动态配置,动态配置可以覆盖静态配置,但只影响当前保存指令。
以SET_NULL为例
-
基于实体的静态配置 (大部分情况下的选择,供绝大部分业务使用)
- Java
- Kotlin
Book.java@Entity
public interface Book {
@OnDissociate(DissociateAction.SET_NULL)
@Nullable
@ManyToOne
BookStore store();
...省略其他代码...
}Book.kt@Entity
interface Book {
@OnDissociate(DissociateAction.SET_NULL)
@ManyToOne
val store: BookStore?
...省略其他代码...
} -
基于保存指令的动态配置 (仅针对单条保存指令,极少数有特殊需求的业务使用)
- Java
- Kotlin
sqlClient
.getEntities()
.saveCommand(book)
.setDissociateAction(
BookProps.STORE,
DissociateAction.SET_NULL
)
.execute();sqlClient.save(book) {
setDissociateAction(
Book::store,
DissociateAction.SET_NULL
)
}