web-dev-qa-db-ja.com

エンティティからDTOへの使用

基本的な階層型Webアプリケーションのフローを考え出そうとしていて、競合する情報をオンラインで読んでいます。私が理解しようとしているのは、なんらかのマッパーを使用して、DAOからサービスレイヤーへのDTOオブジェクトを引き続き使用する利点があるかどうかです。

私が予測する基本的なフローは次のとおりです。

  1. UIモデル/フォーム->コントローラ
  2. コントローラーはモデルをドメインオブジェクト(エンティティ)に変換します
  3. ドメインオブジェクト->サービスレイヤー
  4. ドメインオブジェクト-> DAO
  5. DAO->ドメインオブジェクト
  6. サービス-> UI
  7. UIはドメインをUIモデルに変換します

DTOに従った場合、DAOはエンティティではなくDTOを返します。 (少なくともJavaでは)エンティティが注釈付きPOJOになり、メモリフットプリントが非常に小さくなったため、いくつかの読み取りを行った後、DTOが少し機能しなくなったようです。

これは事実ですか、それともDTOを使用してドメインオブジェクトをDAOレイヤー内に完全にカプセル化する必要がありますか?その場合、サービスレイヤーはDAOに何を渡しますか?

本当にありがとう!

15
dardo

私によると、たとえばJPAによって管理されるBeanなどの永続化可能なPOJOを渡すことは、良い習慣ではありません。

どうして?

主な理由は3つあります。

  1. レイジーコレクションの潜在的な問題。 http://Java.dzone.com/articles/avoid-lazy-jpa-collections
  2. エンティティには動作が含まれている必要があります( 貧血ドメインモデル)とは逆に )UIに予期しない動作を呼び出させたくない場合があります。
  3. 貧血ドメインモデルの場合、モデルに変更を加えるたびにUIが壊れる可能性があるため、モデル構造をUIに公開したくない場合があります。

サービスレイヤーにエンティティを対応するDTOに双方向で変換させることをお勧めします。 DAOはまだエンティティを返します(変換を確実にするのはその仕事ではありません)。

20
Mik378

この議論が繰り返し出てくると思う理由の1つは、必要なすべてのデータを含むオブジェクトを取得し、それを同一またはほぼ同一に見えるオブジェクトに変換することは非常に面倒なことのように思われるためですあなたは引き渡します。

それは本当です、それはピタです。しかし、そうする理由はいくつかあります(上記に列挙したもの以外に)。

  • ドメインオブジェクトは非常に重くなり、呼び出しには役に立たない情報が多く含まれる可能性があります。すべてのデータが送信、マーシャリング/アンマーシャリング、解析されるため、この膨張によりUIの速度が低下します。 FEがWebサービスを参照し、AJAXまたはその他のマルチスレッドアプローチ)で呼び出される多数のリンクがあると考えると、UIがすぐに遅くなります。これにより、一般的なスケーラビリティが得られますウェブサービス
  • 大量のデータを公開することにより、セキュリティが簡単に侵害される可能性があります。 DTOの結果からそれらを排除しなければ、少なくともユーザーの電子メールアドレスと電話番号を公開する可能性があります。
  • 実用的な考慮事項:1つのオブジェクトが永続化ドメインオブジェクトおよびDTOとしてパレードするには、コードよりも多くの注釈が必要です。オブジェクトがレイヤーを通過するときのオブジェクトの状態の管理には、多くの問題があります。一般に、これは管理するPITAよりもはるかに多く、ドメインオブジェクトからDTOにフィールドをコピーするという単調な作業を実行するだけです。

ただし、変換ロジックをコンバータークラスのコレクションにカプセル化すると、かなり効率的に管理できます。

LambdaJを見て、 'convert(domainObj、toDto)'を実行できます。コレクションで使用するために、このオーバーロードがあります。以下は、それを利用するコントローラーメソッドの例です。ご覧のとおり、それほど悪くはありません。

    @GET
    @Path("/{id}/surveys")
    public RestaurantSurveys getSurveys(@PathParam("id") Restaurant restaurant, @QueryParam("from") DateTime from, @QueryParam("to") DateTime to) {

        checkDateRange(from, to);

        MultiValueMap<Survey, SurveySchedule> surveysToSchedules = getSurveyScheduling(restaurant, from, to);
        Collection<RestaurantSurveyDto> surveyDtos = convert(surveysToSchedules.entrySet(), SurveyToRestaurantSurveyDto.getInstance());
        return new RestaurantSurveys(restaurant.getId(), from, to, surveyDtos);

    }
13