2015-12-21 35 views
1

我有一個場景,我有2個標籤需要配置。標籤的名稱是「Out Date」和「In Date」。數據庫中只有一個名爲'Date'的字段。無論是「Out」還是「In」,在運行時由Enum'Scenario'的值決定。但是,我需要實際顯示用戶輸出日期& In Date,以便他可以選擇1或兩者。我聽說JPA將爲此提供計算領域概念。這是真的還是有其他方式可以實現這一點。以下是一些示例代碼。計算屬性與JPA。這是否適用於我的情況?

日期

@Override 
@Convert("DateTimeConverter") 
@Column(name = "DATE") 
public DateTime getDate() { 
    return date; 
} 

情景

@Override 
@Convert("EnumConverter") 
@Column(name = "SCENARIO") 
public Scenario getScenario() { 
    return scenario; 
} 

方案是與值的任何枚舉OUT(1),IN(2)

+0

你好,你終於找到了一個適當的解決你的問題? –

回答

2

有在JPA沒有計算性能。

您可以使用@Transient註解來創建不持續,但基於其他領域的計算性能:

@Transient 
public DateTime getInDate() { 
    if (scenario == Scenario.IN) { 
     return date; 
    } 
    return null; 
} 

@Transient 
public DateTime getOutDate() { 
    if (scenario == Scenario.OUT) { 
     return date; 
    } 
    return null; 
} 

或者,如果你正在使用Hibernate就可以使用專有的註解@Formula

@Formula("case when SCENARIO = 2 then DATE else NULL end") 
@Convert("DateTimeConverter") 
private DateTime inDate; 

@Formula("case when SCENARIO = 1 then DATE else NULL end") 
@Convert("DateTimeConverter") 
private DateTime outDate; 

我更喜歡第一個選項,因爲:

  • 更容易與單元測試測試
  • 它更容易使用單位的實體測試
  • 它不需要專有擴展
  • 一般可能有一些問題與SQL的便攜性,雖然在這個問題case when是SQL 92兼容,因此在這裏不適用

我能唯一的問題是是,在最簡單的方法是我們通過暴露於實體(scenariodate屬性)的客戶內部放棄封裝。但是你總是可以隱藏這些屬性,訪問者protected,JPA仍然會處理該屬性。

+0

沒有計算屬性,但JPA回調有助於計算實體加載後的屬性。 –

1

要計算JPA實體內的屬性,可以使用JPA回調。

看到這個Hibernate JPA Callbacks文檔。 (注意:JPA回調不是特定於休眠,它是最新JPA 2.1 specification的一部分)。 而且這個OpenJpa JPA Calbacks之一。

繼實體生命週期類別有事件可以由實體管理器進行攔截調用方法:

因此,讓我們說你要計算complexLabel標籤從兩個堅持實體領域中的實體LABEL1LABEL2題爲myEntity所

@Entity 
public class MyEntity { 

    private String label1; 

    private String label2; 

    @Transient 
    private String complexLabel; 

    @PostLoad 
    @PostUpdate // See EDIT 
    // ... 
    public void computeComplexLabel(){ 
     complexLabel = label1 + "::" + label2; 
    } 
} 

由於@Dawid寫道,你必須標註complexLabel@瞬變爲了讓它們被持久化忽略。如果你不這樣做,持久化失敗,因爲在MyEntity對應的表中沒有這樣的列。

隨着@PostLoad註釋,computeComplexLabel()方法是通過實體管理器只是myEntity所從持久性的任何實例的加載後調用。 因此,@PostLoad帶註釋的方法最適合放置您的後期加載實體屬性增強代碼。

婁是從JPA 2.1規範關於負荷後的提取物:

一個實體的負荷後方法一直 實體加載到從數據庫或 當前的持久性的上下文之後調用刷新操作已應用於它之後。 PostLoad 方法在返回或訪問查詢結果之前調用,或者在遍歷關聯之前調用 。

編輯

正如指出的@Dawid,你也可以使用@PostUpdate的情況下,要計算只是實體更新後,這個短暫的領域,並在需要時使用其他的回調。

+0

這是另一種選擇。但是,這種方法的問題是,當您更改實體時,以這種方式計算的屬性不會更新。您還需要使用'@ PostUpdate'註釋。坦率地說,使用可輕鬆計算的JPA生命週期方法會導致不必要的複雜性並使單元測試變得更加困難。另外,你需要非常小心。對於處於分離狀態的實體生命週期方法(特別是'@ PostUpdate')將不起作用,給你留下陳舊的數據。 –

+0

我同意你@Dawid的PostUpdate(因爲你經常想在實體更新後再次計算這個計算的屬性)。但是,使用JPA回調會優化此計算,因爲只有在加載(@PostLoad)或更新(@PostUpdate)後纔會執行此計算,但每次獲取該值時都不會執行此操作,請按照您的示例調用getter。然後,我使用getter來保持簡單,所以它們不計算任何東西,只是返回字段值。關於測試,我用集成或組件測試來說明這個問題,它使用真實數據庫或內存數據庫的持久性單元進行測試。 –

+0

在計算需要大量資源的情況下,我同意@Rémi。然後我們可以考慮使用JPA生命週期方法。然而,在大多數情況下,特別是在問題中描述的一種情況下,恕我直言表現的收益並不能證明引入的複雜性(如果我說得對,只有1條表述)。一些團隊成員可能不知道或從未使用過JPA生命週期方法。編寫簡單單元測試代替集成測試和複雜設置的可能性也是很誘人的。 –

相關問題