2017-08-11 77 views
3

我目前面臨一個非常奇怪的問題。Bean驗證@ElementCollection和@Version衝突並且驗證失敗

我有一個實體,其中包含屬性是一個元素集合。

@ElementCollection(targetClass=Integer.class, fetch = FetchType.EAGER) 
@CollectionTable(name="campaign_publisher", [email protected](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 
private Long etag = 0L; 

... 

public Long getEtag() { 
    return etag; 
} 

public void setEtag(Long etag) { 
    this.etag = etag; 
} 

通過添加@Version註釋@NotEmpty驗證我的發佈者集合總是返回無效。

要嘗試和診斷這個我試過如下:

  • 在實體層面創建自定義的驗證,所以我可以在實體檢查值。我發現Set的值已被替換爲一個空的PersistentSet,導致驗證始終失敗。

  • 我創建了使用該從validationfactory檢索到的驗證,這似乎驗證按預期方式工作的實體一些單元測試。

  • 我也試圖給ElementCollection更改爲許多一對多關係和雙向一個一對多的,但問題仍然存在。

現在我不知道了。我唯一能找到的工作是在保存數據之前禁用hibernate驗證並手動調用驗證器。

所以我的問題是:

  • 有沒有人遇到這個問題之前?
  • 關於接下來我可以嘗試的任何建議?

謝謝大家的閱讀!

回答

4

簡短回答:設置初始值爲etag = null

// this should do the trick 
@Version 
private Long etag = null; 

較長的一個:當您通過在字段中添加@Version批註與你正在休眠/彈簧數據的默認值增加一個樂觀鎖認爲,實體是不是一個新的(甚至是ID爲null)。因此,在初始保存而不是堅持實體undelying庫嘗試進行合併。並且暫時的實體力量將hibernate逐一複製,將源實體(即持久化的)的所有屬性複製到目標實體(這是通過休眠將所有屬性設置爲默認值,即空值自動創建的),然後來到這個問題,因爲hibernate只會複製FROM_PARENT類型的關聯值,或者換句話說只有在實體端擁有的關聯值,但在您的情況下關聯值爲TO_PARENT(從子級到父級的外鍵),hibernate將嘗試推遲關聯主實體保存後持久,但保存不起作用,因爲實體不會通過@NotEmpty驗證。

+0

嘿,謝謝你的回答。它幫助我解決了這個問題。解釋也非常詳細。當它讓我時,我會獎賞你的賞金。再次感謝人! –

1

首先,我會建議刪除您的@Version屬性的默認值初始化。這個屬性由hibernate維護,並且應該由它初始化。

第二:你確定你正在驗證完全構造的實體嗎?即你正在構建一些東西,然後做一些事情,並且爲了確切的堅持/沖洗循環,你的實體處於錯誤狀態。

爲了澄清這一點,當你在一個春天的一面,我會建議你DAO層上引入服務水平的驗證。即在初始調用DAO期間強制bean驗證,而不是在flush期間對實體進行bean驗證(yeap hibernate批量處理大量事情,並且僅在刷新週期中進行確切的驗證)。

要做到這一點:標記您的DAO @Validated,使你的函數參數beign驗證:FancyEntity store(@Valid @NotNull FancyEntity fancyEntity) { fancyEntity = em.persist(fancyEntity); em.flush(); return fancyEntity;}

通過使這一點,你一定會認爲你是存儲有效的實體:被稱爲存儲方法之前會發生的驗證。這將揭示你的實體變得無效的地方:在你的服務層,或在不良行爲的休眠層。

0

我注意到你使用混合訪問:方法和字段。在這種情況下,你可以嘗試設置@Version的方法:

@Version 
public Long getEtag() { 
    return etag; 
} 

不是在球場上。

+0

感謝您的回答,我確實嘗試過,但沒有解決問題 –