Как сопоставить DTO с существующим объектом JPA?

Я пытаюсь сопоставить объект Java DTO с существующим объектом объекта JPA без необходимости делать что-то вроде следующего:

public MyEntity mapToMyEntity(SomeDTO dto, MyEntity entity) {
    entity.setField1(dto.getField1());
    entity.setField2(dto.getField2());
    ...
    entity.setField20(dto.getField20());

    return entity;
}

До сих пор я использовал ModelMapper вот так: MyEntity entity = modelMapper.map(dto, SomeDTO.class);, но вместо этого я пытаюсь сопоставить существующий объект объекта, а не создание нового объекта объекта из DTO. Я просмотрел руководство по ModelMapper и не смог найти, как сопоставить без создания нового объекта. Я застрял, добавляя каждую переменную-член вручную для каждого объекта сущности, который у меня может быть?


person dyslexit    schedule 03.10.2017    source источник


Ответы (5)


Вы можете использовать dozer mapper или gson.

DozerMapper ex:

Mapper mapper = DozerBeanMapperBuilder.createDefault();
DestinationObject destObject = mapper.map(sourceObject,DestinationClassName.class);

Вы можете проверить страницу github для получения дополнительной информации.

person Sahin Yanlık    schedule 03.10.2017
comment
Хотя это хорошее предложение, я не думаю, что оно чем-то отличается от того, что на самом деле делает ОП. OP спрашивает, как сопоставить DTO с существующим экземпляром сущности, а не с новым экземпляром. Что-то вроде mapper.map(dto, entityObj), наверное. - person dic19; 14.12.2017

Вы можете определить следующий класс:

public class ObjectMapperUtils {

    private static ModelMapper modelMapper = new ModelMapper();

    /**
     * Model mapper property setting are specified in the following block.
     * Default property matching strategy is set to Strict see {@link MatchingStrategies}
     * Custom mappings are added using {@link ModelMapper#addMappings(PropertyMap)}
     */
    static {
        modelMapper = new ModelMapper();
        modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
    }

    /**
     * Hide from public usage.
     */
    private ObjectMapperUtils() {
    }

    /**
     * <p>Note: outClass object must have default constructor with no arguments</p>
     *
     * @param <D>      type of result object.
     * @param <T>      type of source object to map from.
     * @param entity   entity that needs to be mapped.
     * @param outClass class of result object.
     * @return new object of <code>outClass</code> type.
     */
    public static <D, T> D map(final T entity, Class<D> outClass) {
        return modelMapper.map(entity, outClass);
    }

    /**
     * <p>Note: outClass object must have default constructor with no arguments</p>
     *
     * @param entityList list of entities that needs to be mapped
     * @param outCLass   class of result list element
     * @param <D>        type of objects in result list
     * @param <T>        type of entity in <code>entityList</code>
     * @return list of mapped object with <code><D></code> type.
     */
    public static <D, T> List<D> mapAll(final Collection<T> entityList, Class<D> outCLass) {
        return entityList.stream()
                .map(entity -> map(entity, outCLass))
                .collect(Collectors.toList());
    }

    /**
     * Maps {@code source} to {@code destination}.
     *
     * @param source      object to map from
     * @param destination object to map to
     */
    public static <S, D> D map(final S source, D destination) {
        modelMapper.map(source, destination);
        return destination;
    }
}

И используйте его для своих нужд:

MyEntity entity = ObjectMapperUtils.map(dto, existingEntity);
person Andrew Nepogoda    schedule 14.12.2017

В настоящее время ModelMapper поддерживает сопоставление также с существующим объектом.

Можно сделать следующее (для псевдо-примера Spring):

MyEntity mye = repository.findById(id);
ModelMapper mm = new ModelMapper();    
mm.map(myDTO, mye);
repository.save(mye):

Я использую версию 2.3.1, но более ранние версии также могут поддерживать эту функцию

person pirho    schedule 17.11.2018

Здесь мы можем использовать Map Struct. Ссылка для справки о том, как его использовать: https://www.baeldung.com/mapstruct

person Abhilash Podishetti    schedule 04.05.2021

В переводе с португальского

https://pt.stackoverflow.com/questions/166438/dto-assembler-como-utiliza-lo-realmente

Используйте Pattern Assembler: вы можете преобразовать Entity в DTO с помощью шаблона ассемблера, но это неправильно (я думаю), это нарушает смысл DTO, который является стандартом для передачи объектов. Обратите внимание, что он может состоять из нескольких сущностей. Правильно использовать набор методов экземпляров объектов в классах сервисов, брать DTO и собирать их как сущности, просто потому, что вы правильно работаете со стандартом.

Но у него есть способ, которым даже если это неправильно, это будет работать, но только связь 1 x 1 между сущностью x DTO, используйте функцию Guava.

Например: для преобразования Translate для преобразования в объекты и списки с помощью

import java.util.ArrayList;
import java.util.List;
import com.google.common.base.Function;

    /**
     * Classe de transformação para popular os dados em DTOs, seguindo o pattern
     * Transfer Object Assembler.
     */
    public class Transformer {

        /**
         * Executa a transformação de um objeto para um DTO.
         * 
         * @param from
         * @param function
         * @return <F, T> T
         */
        public static <F, T> T transform(F from, Function<? super F, ? extends T> function) {
            return (from == null) ? null : function.apply(from);
        }

        /**
         * Executa a transformação de uma lista de objetos para uma lista de DTOs.
         * 
         * @param fromList
         * @param function
         * @return <F, T> List<T>
         */
        public static <F, T> List<T> transform(List<F> source, Function<? super F, ? extends T> function) {
            List<T> out = new ArrayList<>(source.size());

            for (F from : source) {
                out.add(function.apply(from));
            }    
            return out;
        }    
    }

Сборщик шаблонов:

import java.util.List;
import br.com.myapp.model.dto.AuthUserDTO;
import br.com.myapp.model.entity.AuthUser;
import com.google.common.base.Function;
import com.google.common.collect.Lists;

/**
 * Classe que transforma entidade USUARIOS em DTO.
 * 
 * @author Dilnei Cunha
 */
public class AuthUserDTOAssembler implements Function<AuthUser, AuthUserDTO>{

    /**
     * Método responsável por fazer a conversão da entidade USUARIOS em um AuthUserDTO.
     */
@Override
public AuthUserDTO apply(AuthUser e) {

    AuthGroupDTO groupDTO = Transformer.transform(e.getAuthGroup(), new  AuthGroupDTOAssembler());

    return new AuthUserDTO(e.getId(),
                       e.getName(),
                       e.getPassword(),
                       e.getEmail(),
                       e.getCreationDate(),
                       e.getLastModificationdate(),
                       e.getLastAccessDate(),
                       e.getAtivo(),
                       e.getUserName(),
                       e.getRamal(),
                       groupDTO);
    }
}

Какой бы сервис использовал эти паттерны...

/**
 * Método responsável por buscar um AuthUserDTO pelo ID do usuário.
 */
@Override
public AuthUserDTO findById(Long id) {
    return Transformer.transform(authUserRepository.findUserById(id), new AuthUserDTOAssembler());
}

Теперь давайте проделаем обратный процесс превращения одного или списка DTO в объекты, но имейте в виду, что ассоциация была 1x1. Для этого просто переверните объекты в реализации функции, например:

import java.util.List;
import br.com.myapp.model.dto.AuthUserDTO;
import br.com.myapp.model.entity.AuthUser;
import com.google.common.base.Function;
import com.google.common.collect.Lists;

/**
 * @author Dilnei Cunha
 */
public class AuthUserAssembler implements Function<AuthUserDTO, AuthUser>{

@Override
public AuthUser apply(AuthUserDTO e) {

        AuthGroup group = Transformer.transform(e.getAuthGroupDTO(), new  AuthGroupAssembler());

        return new AuthUser(e.getId(),
                           e.getName(),
                           e.getPassword(),
                           e.getEmail(),
                           e.getCreationDate(),
                           e.getLastModificationdate(),
                           e.getLastAccessDate(),
                           e.getAtivo(),
                           e.getUserName(),
                           e.getRamal(),
                           group);
        }
    }
person Dilnei Cunha    schedule 03.10.2017