我有以下场景:
第一个
当我尝试执行以下操作时
@Transactional
public void test() {
var adGroup = adGroupRepository.findAll().stream().limit(1000).filter(adGr -> adGr.getId() == 142)
.findFirst().get();
var supervisor = adGroup.getSupervisors().iterator().next();
adGroup.removeSupervisor(supervisor);
adGroupRepository.save(adGroup);
}
预期adGroupRepository.save(adGroup)
将在adGroup
上执行更新级联,而Set<SupervisorEntity> supervisors
上的约束@Size(min = 2)
将触发异常。我尝试调试DefaultFlushEntityEventListener::dirtyCheck
,但我看到旧实体和新实体包含相同大小的supervisors
。请任何人向我澄清我的错误所在以及如何触发此约束的更新/检查?
UPD在日志和数据库中,我看到主管已成功删除
2022-10-23 10:37:07.022 DEBUG [4b5430e5fcb074b6,4b5430e5fcb074b6] 93041 - [8080-exec-1] org.hibernate.SQL : \n delete \n from\n public.groups_supervisors \n where\n id=?
Hibernate:
delete
from
public.groups_supervisors
where
id=?
2条答案
按热度按时间gmxoilav1#
对于延迟加载的关联Map,建议将验证注解放在getter上,而不是放在字段上,因为文档中提到了以下原因:
如果要验证延迟加载的关联,建议在关联的getter上设置约束条件。Hibernate ORM使用代理示例替换延迟加载的关联,代理示例在通过getter请求时进行初始化/加载。如果在这种情况下将约束条件设置在字段级别,则使用实际的代理示例,这将导致验证错误。
所以请尝试:
t1rydlwq2#
似乎我发现了问题。这是由于Hibernate将注入到
Set
字段的类型。当您执行findAll
时,默认情况下,Set
字段将作为PersistenSet
类型注入。这是您的业务逻辑端和Hibernate的dirty check mechanism
之间的共享引用。因此,当您该操作触发
DefaultFlushEntityEventListener::dirtyCheck
。但由于final Object[] loadedState = entry.getLoadedState();
保留shared reference
,因此对于休眠,实体似乎未更改实体的状态。这就是未发生验证错误的原因(但子实体将按预期通过孤立删除删除)PS如果您将更改实体的任何字段,则将按预期执行验证