2014-01-07 14 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を受け取り、Entity全体を戻します。次に、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を実際のEntityにコピーしてEntityManagerとマージすることができるようなもの。

+1

いくつかのコード行を節約するために、apache commons-BeanUtilsライブラリを使用することができます。ここで見てくださいhttp://commons.apache.org/proper/commons-beanutils/apidocs/org/apache/commons/beanutils/BeanUtils.htmlそれは、リフレクションを使ってpojoから/にプロパティをコピーするユーティリティメソッドを持っています – gipinani

答えて

1

あなたの問題に直接対処するバリューオブジェクトデザインパターンを見てください。

このチュートリアルでは、値オブジェクトを紹介します。

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に組み込む必要があります。

Entityバージョンを使用せず、REST GETメソッドとPUTメソッドの間で元の行が変更された場合、エンドユーザーが実際に認識していない変更を上書きします。

エンティティ(作成、更新、削除)を変更する必要があるときはいつでも、私はJPA and Hibernate Optimistic Locking mechanismに頼っています。

UIリスト、テーブル、検索結果の場合元のエンティティの投影にのみ関心があるため、DTOは実行可能なオプションです。 JPAでサポートされていない他のSQL機能(ウィンドウ関数)を使用すると、検索のスピードアップを図ることができます。

+1

エンティティ全体を送信し、それを元に戻すことは危険です。 creationDateやloginなどの特定の画面で変更されないようなフィールドを持つCustomerエンティティを想像してください(エンティティでは読み取り専用として定義されていません)。エンティティ全体がJSONとして送信され、戻ってマージされた場合()、適切なフィールドのみが変更されたことをどのように保証できますか?このような場合(私はかなり一般的だと思います)、エンティティのビューを持つ元のソリューションはより適切なようですね。そして、@Versionはアップデートの紛失から保護しますか? – Lucian

+1

これらの属性に対してupdatable = falseを設定できます –

0

あなたが説明しているような音は、正確にはBlaze-Persistence Entity Viewsのために作られています。現在のリリースでは、読み取りモデル、つまりクライアントに送信するモデルを作成することしかできませんが、書き込みモデルの部分はほぼ完了しています。エンティティビューは、インタフェース/抽象クラスDTO表現とエンティティモデルとの間をマッピングする。ライブラリは、あらゆる種類のパフォーマンスの最適化を実現するためにできるだけ優れたマッピング情報を活用します。

関連する問題