2014-01-07 68 views
16

我正在尋找一種從JPA實體創建數據傳輸對象(DTO)的好方法,反之亦然。 我想將DTO作爲JSON發送給客戶端,然後接收修改後的DTO並將其保存回數據庫。 從JSON解析到它的Java類後,從接收對象的EntityManager中執行合併方法將是最容易的。JPA模式:從實體生成數據傳輸對象DTO並將DTO合併到數據庫

例如有以下實體和保存修改的對象的休息方法:


@Entity 
@Table(name="CUSTOMER") 
public class Customer { 
    @Id 
    Long id; 
    @Version 
    Long version; 
    String name; 
    String address; 
    String login; 
    String password; 
    String creditCardNumber; 
    @OneToMany(cascade = CascadeType.ALL) 
    List<Foo> fooList; 

    ... Getter() and Setter() 
} 

private EntityManager em; 
@POST 
@Path("/saveCustomer") 
public void saveCustomer (Customer customer) {    
    em.merge(customer); 
    return; 
} 

這隻要我發送整個實體類的工作正常JSON並接收整個實體。然後EntityManager將修改後的對象合併到數據庫中。但是,當我只希望提供實體的一個子集(如僅名稱和客戶的地址),就會出現問題:

  1. 什麼是創建一個實體的一個子集的最佳方式?

    - 用手寫實體的DTO?這將爲實體的每個子集生成重複的代碼,必須予以維護。

  2. 如何將作爲實體子集的DTO合併回數據庫?

    - 使用EntityManager的merge()方法不起作用。起初DTO不是實體,因此不能合併。而從DTO創建一個實體,在實體中會有一些未設置的值。合併後,數據庫中的值將爲NULL。我想出了


一個想法,就是爲每個子集我想有一個實體的指定其他實體。 (像數據庫視圖)這將是重複的代碼,但它可以解決DTO與數據庫合併的問題。 (也許這個代碼可以自動生成)

例如實體CustomerView1鏈接到與Customer類相同的表,但僅提供客戶的名稱和地址。它是真正的Customer類的DTO,可以作爲JSON發送並在服務器之外進行修改。這個類也可以被EntityManager合併到數據庫中。

@Entity 
@Table(name="CUSTOMER") 
public class CustomerView1 { 
    @Id 
    Long id; 
    @Version 
    Long version; 
    String name; 
    String address; 
     
        ... Getter() and Setter() 
}     

,但我對這個解決方案的疑慮,我不知道這是否會惹實體的JPA的緩存,並可能導致一些問題。


我的問題是,有沒有解決的DTO碼重複和合並的DTO回數據庫的模式?

或者是否有爲此目的的圖書館? - 像DTO的自動生成和將DTO複製回實際實體那樣的東西,可以將它們與EntityManager合併。

+1

爲了節省一些代碼行你可以使用apache commons-BeanUtils庫。在這裏看看http://commons.apache.org/proper/commons-beanutils/apidocs/org/apache/commons/beanutils/BeanUtils.html它有實用的方法,從pojo複製屬性到反射 – gipinani

回答

1

查看直接解決您的問題的Value Object設計模式。

本教程對值對象進行了很好的介紹。

http://www.javastuff.in/2012/04/value-object-pattern.html

+3

價值對象一般意味着除鏈接文章中描述的以外的其他內容。雖然這些條款沒有被編纂,但最好遵循主流。例如。請參閱http://www.adam-bien.com/roller/abien/entry/value_object_vs_data_transfer – xmedeko

+0

Thx您的評論+1 – Diversity

4

如果實體和DTO之間的大小差異不顯着,你可以選擇發送的實體。

使用DTO時,爲了克服併發性問題(如lost update),您必須將實體版本合併到您的DTO中。

如果您不使用實體版本,並且基礎行在REST GET和PUT方法之間更改,那麼您將覆蓋最終用戶並未真正意識到的更改。

每當我必須改變一個實體(創建,更新,刪除),我依靠JPA and Hibernate Optimistic Locking mechanism

對於UI列表,表格和搜索結果DTO是一個可行的選項,因爲您只對原始實體的投影感興趣。這樣可以加快檢索速度,並且可以從JPA不支持的其他SQL功能(窗口函數)中受益。

+1

有時,發送整個實體並將其合併可能會很危險。設想一個Customer實體具有諸如creationDate或login之類的字段,這些字段不打算被該特定屏幕修改(​​但它們沒有被定義爲只讀實體)。如果整個實體以JSON形式發送,然後接收併合並(),那麼如何保證只有相應的字段已被更改?在這種情況下(我認爲這很常見),具有實體「視圖」的原始解決方案似乎更合適,不是嗎? @Version可以防止丟失的更新,不是嗎? – Lucian

+1

您可以在這些屬性上設置updatable = false –

0

聽起來像你所描述的正是Blaze-Persistence Entity Views已被作出。當前版本只支持創建讀取模型,即發送給客戶端的模型,但寫入模型部分已接近完成。實體視圖映射在接口/抽象類DTO表示和實體模型之間。該庫充分利用映射信息,儘可能實現各種性能優化。

相關問題