2011-12-15 108 views
2

我目前正在重構已使用JPA的應用程序,但JPA EnitytManager(和事務)當前的作用域爲DAO層。還有一個存儲庫層和一個服務層。我想使服務層成爲事務性的,並且在服務層上每個請求有一個EntityManger。理想情況下,我不希望我的服務或存儲庫層知道關於JPA的任何信息。JPA模型驗證和事務處理

當前存儲庫和服務層使用從DAO層獲得的分離實體。對模型進行更改並將實體合併回DAO層。在新結構中,實體在整個請求期間保持被管理,並且1個請求包含在1個事務中。變更在交易結束時自動提交。這看起來更像JPA的精神,並且在最常見的情況下工作得很好。

雖然有時會對模型進行更改,然後對模型進行驗證。如果模型無效,則不應保存更改。在舊的結構中,這很簡單:

在這個例子中,過程基本上是一個圖,整個圖必須驗證,沒有自引用,每個節點都必須可達,第一個節點有一些特殊需求,成爲最終節點等等。我們首先對模型進行修改,然後驗證模型。

庫層的代碼的時候:

changeProcessModel(); 
messages = ProcessValidator.validate(process); 
if (messages.hasNoErrors()) { 
    processDao.merge(process); 
    messages.addInfoMessage("Process was updated succesfully"); 
} 
return messages; 

在新的結構,我想我有三種選擇,我哪一個被認爲是最好的做法質疑,或是否有任何其他的替代品。

新的代碼選項1:

changeProcessModel(); 
messages = ProcessValidator.validate(process); 
if (messages.hasNoErrors()) { 
    messages.addInfoMessage("Process was updated succesfully"); 
} else { 
    throw new InvalidProcessException(messages); 
} 
return messages; 

此代碼濫用的排序爲一些業務規則驗證一個RuntimeException。我不認爲這被認爲是最佳做法,但交易是回滾的。這也與Bean Validation實例兼容,如果實體不驗證,它也會引發異常。

新的代碼選項2:

changeProcessModel(); 
messages = ProcessValidator.validate(process); 
if (messages.hasNoErrors()) { 
    messages.addInfoMessage("Process was updated succesfully"); 
} else { 
    em.getTransactionManager.rollback(); 
} 
return messages; 

此代碼直接做在JPA TransactionManager回滾,並介紹了我的倉庫層和JPA之間的相關性。

新的代碼選項3:

changeProcessModel(); 
messages = ProcessValidator.validate(process); 
if (messages.hasNoErrors()) { 
    messages.addInfoMessage("Process was updated succesfully"); 
} else { 
    processDao.refresh(process); 
} 
return messages; 

這段代碼看起來很不錯,但它不依賴於CascadeType.REFRESH就需要刷新的過程中實體間關係正確設置。

我也可以例如到processDao.clear();processDao.rollback();但是這增加了processDao的範圍到整個entityManger。我不確定這是否是一種非常乾淨的方法。

你對此有何看法?

回答

0

我認爲你對域名持久性的瞭解程度越低越好。因此,在與約見到持續性作爲域模型的服務,而不是把它看作模型我建議以下解決方案的一部分想法線:

  • 域必須是一致的狀態,始終;
  • 所以;進入模型的變化(來自服務,你有什麼樣的UI)不能改變模型,而不知道將來的模型是否被驗證。
  • 含義:當前模型始終保持一致。

在公式中:Future model = CurrentModel.PerformChanges()。Validated();

這怎麼辦?可能使用一種工作單位類型的建築。 (http://martinfowler.com/eaaCatalog/unitOfWork.html) 每當一個domainobject被更改並被驗證時,就會引發一個被更改的事件。單位工作管理器負責提取這些事件,然後確保將這些內容放入數據庫中。如果更改無效,則不會引發該事件,並且該模型被標記爲「無效」。因爲你在隔離模式下工作,所以這不是問題。當您在共享域模型中工作時,更改必須在您的域中回滾!

這可能是解決方案中最具學術性的方法,但也許它有助於開始討論,在這些情況下做什麼......