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更改为多对多关系和双向一对多关系,但问题仍然存在

现在我没有主意了。我发现唯一可以正常工作的方法是禁用hibernate验证,并在保存数据之前手动调用验证程序

因此,我的问题是:

  • 以前有人遇到过这个问题吗
  • 对我下一步可以尝试什么有什么建议吗

谢谢大家的阅读

首先,我建议删除@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;
}