2012-11-23 78 views
2

我們遇到了一個問題,我們必須維護一個日期字段 - 並最好保留其值 - 其中日期字段依賴於其他實體'狀態。用JPA2 + Hibernate + Spring解決這個問題的正確方法是什麼?更新依賴於其他實體狀態的@Entity字段的正確方法

基本上,我們有三個實體,我們稱它們爲Parent,ChildConfdependentDate由依賴於其他實體狀態的複雜業務規則計算得出。具體來說,應該是Parent#date減去Conf#delay跳過所有周末或節假日(持續數據)。

問題是,只要Parent#date發生變化,應該重新計算所有孩子的dependentDate。每當Child對象的conf發生更改時也會發生這種情況。目前,有一種基於Child對象關係計算新日期的服務方法(我們稱之爲calculateDate())。

我們面臨着應該計算字段值的問題。我想出了三種可能的解決方案。哪些這些 - 或者可能是別的 - 是更新依賴於其他實體狀態的實體字段的首選方式?

  1. 一個JPA EntityListener
    • 並不鼓勵這樣的JPA2規範,因爲EntityListeners不應訪問其他實體
    • 領域將永遠是正確的
  2. 一個Spring AOP的方面的更新
    • 該邏輯被隱藏在其他一些類別中,不容易看到
    • 的切入點不抓的風險都堅持/更新事件
  3. 每個開發者爲自己
    • 始終,更新或者父母或子女類的實例時,開發者必須記住調用該服務的calculateDate()方法
    • 這應該在道或服務層?顯影劑忘記加呼叫的
    • 風險,從而導致錯誤的狀態

下面的示例示出了其中省略註解配置的實體關係。

的實體

public class Parent { 
    LocalDate date; 
    Set<Child> children;  // one-to-many 
} 

public class Conf { 
    int delay; 
} 

public class Child { 
    LocalDate dependentDate; 
    Conf conf;    // many-to-one 
    Parent parent;   // many-to-one 
} 
+0

這不應該是一個答案,但更多的是「選項4」:您可以在數據庫中添加一個觸發器,用於在更新其他表格時更新日期字段。這當然只適用於以下情況:a)你的dbms支持觸發器,b)你願意將業務邏輯移出主軟件,c)你的實體是「無狀態的」(就像在彈簧mvc設置中一樣)。 – realsim

+0

@realsim「無狀態」實體的含義是什麼?正如我所看到的,實體只是一個狀態(免責聲明,我知道JPA但不是Spring) – SJuan76

+0

我的意思是在提交hibernate會話之後,它不會再被使用(因爲觸發器實體不在會議認爲他們的狀態)。如果會話將被重用,它將以StaleObjectStateException結束。但是如果會話因爲請求/響應完成而關閉,並且下一個請求會創建另一個會話,那麼這種方法就沒有問題。 - 我不喜歡自己移動業務邏輯,但有時觸發器是必需的... – realsim

回答

2

依賴於多個實體狀態的複雜業務規則屬於服務層。應用程序中不應有太多地方需要更改父級日期和孩子的機密,所以您不應該有太多需要完成新日期計算的地方。

如果你真的有這麼多地方完成了這個工作,你可以清楚地知道日期必須通過將ChildDateUpdater實例(ChildDateUpdater作爲接口)傳遞給父日期的設置者和設置者來重新計算孩子conf。這將使明顯,必須採取一些措施每隔這兩個領域都改變時間:

在家長:

public void setDate(Date date, ChildDateUpdater childDateUpdater) { 
    this.date = date; 
    for (Child child : children) { 
     childDateUpdater.updateChildDate(child); 
    } 
} 

兒童:

public void setConf(Conf conf, ChildDateUpdater childDateUpdater) { 
    this.conf = conf; 
    childDateUpdater.updateChildDate(this); 
} 
+0

我們最終在'model'包中創建了接口,並在服務層中創建了相應的實現。依賴字段的setter被公開,但'Conf'和'Parent'的日期設置者被提供了更新接口。 – RJo

0

封裝在DAO數據訪問。當要保存Parent時,請檢查其值是否有任何更改,如果是,則相應地更新孩子。

realsim觸發選項也是可行的(基本上是在不同層面實施了同樣的想法),但是你會失去便攜性(也有將與已加載未更新孩子的情況下,問題)。

+0

使用JPA/Hibernate,DAO通常用於從數據庫檢索數據。這些數據以實體的形式返回,可以更改它們的狀態並自動保存到數據庫中。典型的JPA應用程序不調用任何DAO.save()方法來修改數據庫。 –

+0

@JBNizet好的,我明白了,我更習慣於EJB的JPA風格。 – SJuan76

+0

EJB的風格與我所描述的相同。 JPA實體附加到一個持久化上下文,並鏈接到事務,並且當事務提交時,所有附加實體的狀態將自動刷新到數據庫。 –

相關問題