Как стать автором
Обновить

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

Используйте в полях Optional — те поля которые не присутсвуют, не будут инициализированы и будут содержать null. Те поля которые были в запросе будут содержать Optional И если значение было null, то Optional будет пуст, если нет — конкретное значение. Плюс вы вообще ничего в структуре и контроле типов не теряете. Единственный минус — возня с Optional.
Собственно, я как раз старался избежать постоянных проверок в коде при маппинге DTO-модель-сущность.
Спасибо за рекомендацию, я попробую реализовать Optional+MapStruct, посмотрю насколько это усложнит код.

На самом деле можно реализовать еще проще: как Optional + Jackson ObjectMapper для простого частичного обновления сущности из ДТО.
У меня есть подробный пример реализации метода PATCH при помощи такого подхода здесь https://github.com/ololx/restful-updating-instances; если Вам будет интересно.


В Вашем случае, это может выглядеть так:
Сущность (без аннотаций Hibernate):


public class UserModel {

    private long id;

    @JsonProperty("login")
    private String login;

    @JsonProperty("first_name")
    private String firstName;

    @JsonProperty("last_name")
    private String lastName;

    @JsonProperty("birth_date")
    private String birthDate;

    @JsonProperty("email")
    private String email;

    @JsonProperty("phone_number")
    private String phoneNumber;
}

ДТО для этой сущности:


@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserDetail {

    @JsonProperty("login")
    private Optional<String> login;

    @JsonProperty("first_name")
    private Optional<String> firstName;

    @JsonProperty("last_name")
    private Optional<String> lastName;

    @JsonProperty("birth_date")
    private Optional<String> birthDate;

    @JsonProperty("email")
    private Optional<String> email;

    @JsonProperty("phone_number")
    private Optional<String> phoneNumber;
}

Кусок реализации метода PATCH:


    @SneakyThrows
    @PatchMapping(
            path = "/{id}"
    )
    public UserDetail update(
            @ApiParam(
                    name="id",
                    value = "The update user entity id",
                    required = true
            ) @PathVariable Long id,
            @ApiParam(
                    name="updateUserRequest",
                    value = "The update user request",
                    required = true
            ) @RequestBody UserDetail updateUserRequest) {
        UserModel user = this.userRepository.findById(id).orElse(null);
        assertNotNull(user, String.format("User with id - {} is not existed", id));

        objectMapper.updateValue(user, updateUserRequest);
        this.userRepository.save(user);

        UserDetail updateUserResponse = new UserDetail();
        objectMapper.updateValue(updateUserResponse, user);

        return updateUserResponse;
    }

Где userRepository — обычный JpaRepository; а objectMapper — стандартный ObjectMapper.


    @Autowired 
    PersonRepository peopleRepository;

    @Autowired
    ObjectMapper objectMapper;
Поддерживаю. Сами используем такой способ.
А что вы пытаетесь сэкономить?
sql БД? Так там вся строка перезаписывается.
Сеть? Протобаф тогда берите.
Серверное время? Тоже протобаф.
Я пытаюсь повысить удобство проброса изменяемых данных через слои приложения. Маппинг из DTO в модель, из модели в сущность.
Ну и, если это bulk update операция, то произвести ее за одну SQL операцию.
Я пытаюсь повысить удобство проброса изменяемых данных через слои приложения. Маппинг из DTO в модель, из модели в сущность.

А может вам не надо столько слоев? Раз экономить их хочется?
Поменьше энтерпрайза, поменьше бойлерплейта. И функциональный кусочек можно вставить где io нет. За такое не бьют давно уже.

Ну и, если это bulk update операция, то произвести ее за одну SQL операцию.

Это надо делать для атомарности в любом случае. Если размер разумный.
А может вам не надо столько слоев? Раз экономить их хочется?

Ну если эти слои уже есть в рамках реализации остальных эндпоинтов, то сэкономить вряд ли получится. Кроме того могут существовать другие условия в процессе partial update, которые потребуют преобразования данных. Например, если часть изменяемых данных относятся к другому микросервису — их нужно перемапить в DTO запроса к другому микросервису и далее отработать остальную логику.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории