Java Bean验证@ElementCollection和@Version冲突,验证失败
我现在面临一个非常奇怪的问题 我有一个实体,它包含一个作为元素集合的属性Java Bean验证@ElementCollection和@Version冲突,验证失败,java,spring,hibernate,validation,Java,Spring,Hibernate,Validation,我现在面临一个非常奇怪的问题 我有一个实体,它包含一个作为元素集合的属性 @ElementCollection(targetClass=Integer.class, fetch = FetchType.EAGER) @CollectionTable(name="campaign_publisher", joinColumns=@JoinColumn(name="campaign_id")) @Column(name = "publisher_id") ... @NotEmpty(messag
@ElementCollection(targetClass=Integer.class, fetch = FetchType.EAGER)
@CollectionTable(name="campaign_publisher", joinColumns=@JoinColumn(name="campaign_id"))
@Column(name = "publisher_id")
...
@NotEmpty(message = "campaign.publishers.missing")
public Set<Integer> getPublishers() {
return this.publishers;
}
public Campaign setPublishers(Set<Integer> publisherId) {
this.publishers = publisherId;
return this;
}
通过添加@Version注释,我的发布服务器集上的@NotEmpty验证始终返回无效
为了尝试并诊断此问题,我尝试了以下方法:
- 在实体级别创建自定义验证器,以便检查实体中的值。我发现值集已被一个空的PersistentSet替换,这导致验证总是失败
- 我为使用从validationfactory检索到的验证器的实体创建了一些单元测试,该验证器似乎按照预期工作
- 我还尝试将ElementCollection更改为多对多关系和双向一对多关系,但问题仍然存在
- 以前有人遇到过这个问题吗
- 对我下一步可以尝试什么有什么建议吗
谢谢大家的阅读 首先,我建议删除@Version属性的默认值初始化。此属性由hibernate维护,应该由它初始化 第二:您确定要验证完整构造的实体吗?i、 你正在构建一些东西,然后做一些事情,对于精确的持久化/刷新周期,你的实体处于错误的状态 为了澄清这一点,当您使用Spring时,我建议在DAO层上引入服务级别验证。也就是说,在对DAO的初始调用期间强制进行bean验证,而不是在刷新期间对实体进行bean验证(yeap hibernate批量处理很多事情,而精确的验证只在刷新周期中发生) 要实现这一点:标记DAO
@Validated
并使函数参数经过验证:FancyEntity存储(@validate@NotNull FancyEntity FancyEntity){FancyEntity=em.persist(FancyEntity);em.flush();return FancyEntity;}
通过这样做,您将确保存储的是有效的实体:验证将在调用store方法之前进行。这将揭示实体失效的地方:在服务层,或者在行为不好的hibernate层 简短回答:设置
etag
=null
的初始值
// this should do the trick
@Version
private Long etag = null;
较长的一个:当您通过在具有默认值的字段上添加
@Version
注释来添加乐观锁定时,您使hibernate/spring数据认为该实体不是新实体(即使id为null
)。因此,在初始保存时,不存在实体的库尝试进行合并,而不是持久化实体。合并瞬态实体会迫使hibernate将源实体(您正在持久化的实体)中的所有属性逐个复制到目标实体(hibernate自动创建,所有属性都设置为默认值,也称为null),问题就来了,由于hibernate只会将的关联值从\u PARENT
类型复制,或者换句话说,只会将实体侧保留的关联(但在您的情况下,关联是到\u PARENT
(从子级到父级的外键),hibernate会在主实体保存后尝试延迟关联的持久性,但是保存将不起作用,因为实体将无法通过验证。我注意到您使用混合访问:方法和字段。在这种情况下,您可以尝试在方法上设置@Version
:
@Version
public Long getEtag() {
return etag;
}
不是在球场上。嘿,谢谢你的回答。它帮助我解决了这个问题。解释也很详细。如果我能得到赏金,我会给你的。再次感谢你,伙计!谢谢你的回答,我试过了,但没有解决问题
@Version
public Long getEtag() {
return etag;
}