2017-07-24 124 views
0

嗨,我強迫Envers問題。每類擴展包含@GeneratedAuto的ID等。有兩個實體BaseEntity:休眠Envers找到OneToMany JoinTable

@Audited 
@Entity 
public class HandballInjury extends Injury { 

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL) 
    @JoinTable(name = "HandballDictionaryFact") 
    private List<HandballDictionaryFact> handballDictionaryFacts = new ArrayList<HandballDictionaryFact>(); 
    private HandballTimeOfInjury timeOfInjury; 

    ... 
} 

而且

@Audited 
@Entity 
@Table(name = "handballDictionaryFact") 
public class HandballDictionaryFact extends DictionaryFact{ 
    ... 
} 

*父母雙方都有@Audited註解。我的問題是,當我在HandballInjury上使用AuditEntity查找方法時,它會返回所有屬於傷害但不關心revisionId的字典數據的正確傷害。在數據庫中,一切都保存正確。我認爲,如果表加入,那麼envers看起來只是如果id是正確的,而不看版本。休眠Envers版本:5.1.0.Final

編輯1:

我發現我不是SessionFactory.openSession打開新的會話()。正因爲如此,envers正在進入1個LevelCache來獲取數據。我修好了,但沒有幫助。多數民衆贊成在如何發起查詢:

result = getReader().find(HandballInjury.class, ((HandballInjury) object).getId(), revisionNumber); 

也許我應該寫自己的查詢?

我注意到下面的查詢還返回了HandballDictionaryFacts_aud中的所有實體,而不是指定的revisionNumber。

List<HandballDictionaryFact> dictionaryFact = getReader().createQuery() 
       .forEntitiesAtRevision(HandballDictionaryFact.class, revisionNumber).getResultList(); 

編輯2: 我發現找到查詢與RevNumber尋找handballDictionaryFact小於或等於handballInjury.RevNumber。我現在的問題是,我可以迫使envers只看起來平等嗎?部分查詢:

 and handballdi1_.REV=(
     select 
      max(handballdi2_.REV) 
     from 
      dictionaryfact_AUD handballdi2_ 
     where 
      handballdi2_.DTYPE='HandballDictionaryFact' 
      and handballdi2_.REV<=? 
      and handballdi1_.id=handballdi2_.id 
    ) 

來自第一次編輯的查詢還檢查revNumber是否小於或等於。

+0

Envers應當施加特別創建的事實中的單個條目'REV'謂詞,以便聚合根的任何關聯(在本例中爲「HandballInjury」)將等於或小於聚合根的關聯。如果您確信它沒有這樣做,請打開一個JIRA票據,並用一個簡單的測試案例來報告問題,以重現錯誤。 – Naros

+0

調試後我發現envers從firstlevelcache而不是數據庫獲取數據。但不知道如何改變這一點。 – MrNetroful

+0

你是說它從Session的1LC或Envers的內部1LC中獲取數據,因爲它們是兩回事。你可以用查詢更新你的文章,以及你如何觀察這種行爲? – Naros

回答

0

我的問題是,當我在HandballInjury上使用AuditEntity查找方法時,它會返回所有屬於傷害但不關心revisionId的dictionaryFacts的正確傷害。在數據庫中,一切都保存正確。我認爲,如果表加入,那麼envers看起來只是如果id是正確的,而不看版本。

這是不可能的,因爲審計跟蹤實際上是如何工作的。

如果您查看審計表,您會注意到在許多情況下,實體的主鍵在審計表中添加了修訂號,以允許多個條目用於同一個實體主鍵。

+----+-----+---------+---------+ 
| ID | REV | REVTYPE | DATA | 
+----+-----+---------+---------+ 
| 1 | 1 |  0 | Initial | 
+----+-----+---------+---------+ 
| 1 | 2 |  1 | Updated | 
+----+-----+---------+---------+ 
| 1 | 3 |  2 |   | 
+----+-----+---------+---------+ 

正如你可以在該圖示看到,該表在這裏有3行對於其中插入的實體相同的實體的主鍵(REVTYPE = 0),更新(REVTYPE = 1),並刪除(REVTYPE = 2)。

如果此表與另一個實體相關聯,我們還需要考慮REV值,以確保基於創建修訂時的時間點關聯是正確的。

讓我們考慮另一個指向上述表ID = 1的實體。如果我們不考慮REV,那麼我們不知道我們應該如何在關聯的審計實體實例上填充DATA字段。應該是Initial還是Updated

這是REV字段必須考慮的另一個原因。

發現我沒有通過SessionFactory.openSession()打開新會話。正因爲如此,envers正在進入1個LevelCache來獲取數據。我修好了,但沒有幫助。

我相信這裏很重要的一點是,Envers使用自己的L1C實現,它獨立於Hibernate Session使用的實現。因爲它實例化對象不是真正管理實體,而是使用實體對象佈局在給定的時間修訂代表了實體的狀態剛剛構造的對象

Envers使用它自己的實現。

我不完全清楚爲什麼你必須改變與會話管理相關的任何東西,除非你的代碼做了其他的模糊處理。

HandballInjury injuryAtRevision = getReader() 
    .find(HandballInjury.class, handballInjury.getId(), revisionNumber); 

上面的查詢基本上都會看,看是否Envers L1C包含HandballInjury對於給定的主鍵和修改的實例。如果是這樣,它會返回它;否則它從數據庫中獲取它。

返回的實例將表示生成指定的revisionNumber值時的狀態HandballInjury,包括任何已審覈的關聯。

也許我應該寫自己的查詢?

爲什麼,您還沒有澄清這個問題。如上所述,查詢完全按照其意圖執行的操作。

我注意到下面的查詢還返回了HandballDictionaryFacts_aud中的所有實體,而不是指定的revisionNumber。

List<HandballDictionaryFact> dictionaryFact = getReader().createQuery() 
    .forEntitiesAtRevision(HandballDictionaryFact.class, revisionNumber) 
    .getResultList(); 

,這是預期的行爲。

如果我們假設我們有兩個事實,一個在修訂版1創建,另一個在修訂版2和上面使用revisionNumber=2,那麼在那個時候,你有兩個實體定義,你不知道?

我可以看到在這裏改進java-doc使其更清晰,但這是預期的行爲。

編輯2:我發現查找查詢正在查找與RevNumber小於或等於handballInjury.RevNumber的handballDictionaryFact。我現在的問題是,我可以強制envers看僅相當於

如果你想是明確的,並在以後查詢的默認範圍某個特定的版本獲得的實體,您可以添加額外的謂詞來返回類型的結果。

List<HandballDictionaryFact> dictionaryFact = getReader().createQuery() 
    .forEntitiesAtRevision(HandballDictionaryFact.class, revisionNumber) 
    .add(AuditEntity.revisionNumber().eq(2)) 
    .getResultList(); 

以相同的假設和以前一樣,在修訂版1創建了一個事實,另一個在修訂版2,這將返回一個包含在版本2