сопоставление объекта с DTO с вложенным DTO

#spring #hibernate

#spring #спящий режим

Вопрос:

У меня реляционная (тяжелая) модель базы данных с большим количеством табличных зависимостей и внешних ключей. Мы решили использовать DTO, чтобы упростить представление данных спереди и скрыть соответствие режиму базы данных.

Но у нас есть DTO с вложенным DTO. И у нас есть классы реализации Mapper для установки данных с помощью небольшой бизнес- / функциональной логики.

Вопрос в том, является ли хорошей практикой, когда класс mapper вызывает mapper (и т. Д.), Или это лучший способ иметь основной класс, обрабатывающий все классы mapper? (Пример 1 или 2)

Пример 1 :

 @Component
public class ActorMapperImpl implements ActorMapper {

    @Autowired
    private InsurerMapper insurerMapper;

    @Autowired
    private PersonMapper personMapper;

    @Autowired
    private CorrespondentMapper correspondentMapper;

    ....

    @Override
    public ActorDto mapToDto(Acteur actor) {
        final ActorDto actorDto;
        
        if (actor != null) {
            ....
            
            actorDto.setPerson(personMapper.personneToPersonDto(actor.getPersonne()));

            
            if (actor.getInsurer() != null) {
                actorDto.setInsurer(insurerMapper.entityToDto(actor.getInsurer()));
            } else if (actor.getCorrespondantAssureur() != null) {
                actorDto.setInsurer(correspondentMapper.correspondentToInsurerDto(actor.getCorrespondantAssureur()));
            }

            ....

            // intermediate
            final Intermediaire intermediate = actor.getIntermediaire();
            if (intermediate != null) {
                .....
                if (person != null) {
                    intermediateDto = personMapper.personneToPersonDto(person);
                    intermediateDto.setQuality(quality);
                } 
                .....
            }
        .....
 

Пример 2 :

 @Service
public class FinancialSlipOrchestratorImpl implements FinancialSlipOrchestrator {

    .....
   

    @Autowired
    private FinancialSlipMapper financialSlipMapper;

    @Autowired
    private PersonMapper personMapper;

    

    ..... some public / private methods

    

    private FinancialSlipDto fullMapToDto(FinancialSlip financialSlip) {
        .....
    
    
        // Financial slip
        var financialSlipDto = financialSlipMapper.mapToDto(financialSlip);

        // person
        financialSlipDto.setIssuerPerson(personMapper.personneToPersonDto(financialSlip.getIssuerPerson()));
        
        ....

        // RIB
        financialSlipDto.setRib(ribMapper.mapToDto(financialSlip.getRib()));

        return financialSlipDto;
    }
 

Комментарии:

1. Не уверен, что здесь лучше всего, но я бы выбрал ручную оркестровку. Таким образом, вы сохраняете контроль и не сталкиваетесь с риском циклических зависимостей.

Ответ №1:

Я бы сказал, что для одного картографа нормально вызывать другого и думать, что это идеальный вариант использования для представлений объектов с сохранением Блейза.

Я создал библиотеку, чтобы обеспечить простое сопоставление между моделями JPA и моделями, определяемыми пользовательским интерфейсом или абстрактным классом, что-то вроде проекций данных Spring на стероидах. Идея заключается в том, что вы определяете свою целевую структуру (модель домена) так, как вам нравится, и сопоставляете атрибуты (геттеры) с помощью выражений JPQL с моделью сущности.

Модель DTO для вашего варианта использования может выглядеть следующим образом с помощью представлений объектов Blaze-Persistence:

 @EntityView(Acteur.class)
public interface ActorDto {
    @IdMapping
    Long getId();
    String getName();
    PersonDto getPerson();
    default InsurerDto getInsurer() {
        return getMainInsurer() != null ? getMainInsurer(): getCorrespondantAssureur();
    }
    @Mapping("insurer")
    InsurerDto getMainInsurer();
    InsurerDto getCorrespondantAssureur();
    IntermediaireDto getIntermediaire();

    @EntityView(Person.class)
    interface PersonDto {
        @IdMapping
        Long getId();
        String getName();
    }
    @EntityView(Insurer.class)
    interface InsurerDto  {
        @IdMapping
        Long getId();
        String getName();
    }
    @EntityView(Intermediaire.class)
    interface IntermediaireDto {
        @IdMapping
        Long getId();
        String getName();
        Integer getQuality();
        PersonDto getPerson();
    }
}
 

Запрос — это вопрос применения представления сущности к запросу, простейшим из которых является просто запрос по идентификатору.

ActorDto a = entityViewManager.find(entityManager, ActorDto.class, id);

Интеграция данных Spring позволяет использовать его почти как проекции данных Spring: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

Самое лучшее в этом то, что он будет извлекать только те данные, которые действительно необходимы.

Если вы также используете DTO для возврата изменений, вы будете рады услышать, что Blaze-Persistence Entity-Views также поддерживает это очень эффективным образом. Это позволит вам избавиться от всех этих написанных вручную картографов 🙂

Комментарии:

1. Спасибо за ответ