엔티티 대 DTO 사용법 객체-> DAO DAO-> 도메인 객체 서비스-> UI UI는

기본 계층 형 웹 응용 프로그램에 대한 흐름을 생각해 내려고 상충되는 정보를 온라인에서 읽었습니다. 내가 알아 내려고하는 것은 일종의 매퍼를 사용하여 DAO에서 서비스 계층으로 DTO 객체를 계속 사용하는 이점이 있는지 여부입니다.

내가 예상하는 기본 흐름은 다음과 같습니다.

  1. UI 모델 / 양식-> 컨트롤러
  2. 컨트롤러가 모델을 도메인 개체 (엔터티)로 변환
  3. 도메인 객체-> 서비스 계층
  4. 도메인 객체-> DAO
  5. DAO-> 도메인 객체
  6. 서비스-> UI
  7. UI는 도메인을 UI 모델로 변환

DTO가 준수되면 DAO는 엔티티가 아닌 DTO를 다시 전달합니다. 약간의 독서를 한 후에 (적어도 Java에서는) 엔티티에 주석이 달린 POJO가되어 DTO가 약간 소진 된 것처럼 보입니다. 즉, 메모리 공간이 매우 작아졌습니다.

이 경우 DAO를 사용하여 DAO 계층 내에서 도메인 개체를 완전히 캡슐화해야하며,이 경우 서비스 계층이 DAO로 전달할 것은 무엇입니까?

무리 감사!



답변

나에 따르면, 예를 들어 JPA가 관리하는 Bean과 같이 지속 가능한 POJO를 전달하는 것은 좋은 습관이 아닙니다.

왜?

세 가지 주요 이유가 있습니다.

  1. 게으른 컬렉션의 잠재적 인 문제. http://java.dzone.com/articles/avoid-lazy-jpa-collections
  2. 엔터티에는 비헤이비어 도메인 모델 과 달리 비헤이비어가 포함되어야합니다 . UI에 예기치 않은 비헤이비어가 호출되도록하지 않을 수 있습니다.
  3. 빈혈 도메인 모델의 경우 모델을 새로 변경할 때마다 UI가 손상 될 수 있으므로 모델 구조를 UI에 노출하지 않을 수 있습니다.

서비스 계층에서 엔티티를 양방향으로 해당 DTO로 변환하는 것을 선호합니다. DAO는 여전히 엔티티를 반환합니다 (변환을 보장하는 것은 아닙니다).


답변

이 토론이 반복적으로 발생한다고 생각하는 이유 중 하나는 필요한 모든 데이터가 포함 된 객체를 가져 와서 동일하거나 거의 동일한 객체로 변환하는 것이 진지한 고통 인 것처럼 보이기 때문입니다. 당신은 전달하고 있습니다.

사실, 그것은 PITA입니다. 그러나 그렇게하는 데는 몇 가지 이유가 있습니다 (위에 열거 된 것 외에).

  • 도메인 개체는 매우 무거워 질 수 있으며 통화에 유용한 정보가 많이 포함되어 있습니다. 이 팽창은 전송, 마샬링 / 비 정렬 화 및 구문 분석 된 모든 데이터로 인해 UI 속도가 느려집니다. FE가 웹 서비스를 참조하고 AJAX 또는 다른 멀티 스레드 접근 방식으로 호출되는 수많은 링크가 있다고 생각하면 UI가 빠르게 느려집니다. 이 모든 것이 웹 서비스의 일반적인 확장 성을 얻습니다.
  • 너무 많은 데이터를 노출하면 보안이 쉽게 손상 될 수 있습니다. 최소한 DTO 결과에서 사용자를 제거하지 않으면 사용자의 이메일 주소와 전화 번호가 노출 될 수 있습니다.
  • 실제 고려 사항 : 하나의 오브젝트가 지속 도메인 오브젝트 및 DTO로 퍼레이드하려면 코드보다 더 많은 주석이 있어야합니다. 레이어를 통과 할 때 개체의 상태를 관리하는 데는 여러 가지 문제가 있습니다. 일반적으로 이것은 도메인 개체에서 DTO로 필드를 간단하게 복사하는 작업을 관리하는 데 훨씬 더 많은 PITA입니다.

그러나 변환 논리를 변환기 클래스 모음으로 캡슐화하면 상당히 효과적으로 관리 할 수 ​​있습니다.

‘convert (domainObj, toDto)’를 수행 할 수있는 lambdaJ를 살펴보십시오. 컬렉션에 사용하기 위해 과부하가 있습니다. 다음은이를 사용하는 컨트롤러 방법의 예입니다. 보시다시피 그렇게 나쁘지 않습니다.

    @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);

    }