Как обновить только входящие поля в модели, используя данные весны jpa? - PullRequest
0 голосов
/ 30 мая 2018

Я использую Spring data jpa для постоянства.Скажем, я должен обновить модель.Эта модель имеет n полей с первичным ключом.

    {
    "some_model":{
        "id":"5527716",
        "field_one": "44248156",
        "field_two": "44248156",
        "field_three": "44248156",
        "field_four": "44248156",
        "field_five": "44248156",
        "field_six": "44248156",
        "field_seven": "44248156",
        "field_eight": "44248156",
        "field_nine":"65037768"     
    }
}

Рассматривая json как представление моей модели, я хочу обновить только те поля, которые входят в json (первичный ключ).Идентификатор, который всегда будет там).Есть ли способ, которым я могу достичь, не проверяя каждое поле явно и не устанавливая их?

Скажем, я получаю запрос вроде:

{
    "some_model":{
        "id":"5527716",
        "field_one": "44248156",
        "field_two": "44248156",
        "field_three": "44248156",

        "field_eight": "44248156",
        "field_nine":"65037768"     
    }
}

Я хочу добиться обновления (upsert вид вещи) просто используя repository.save или что-то подобное.В настоящее время при использовании метода save репозитория внутренне обновляется модель с использованием значения primaryKey, но в качестве значений для отсутствующих полей устанавливается значение NULL.Я хочу, чтобы эти поля остались без изменений.

Основная проблема: есть сотни моделей, и каждая модель имеет около 10-15 полей, и явная проверка каждого поля и обновление для всех моделей было бы кошмаром.

Я также проверил аннотацию @DynamicUpdate, но, похоже, она применима для явной настройки, где сгенерированный sql оптимизирован.

Буду признателен за любые идеи по этому поводу.

Ответы [ 3 ]

0 голосов
/ 30 мая 2018

Обычно слияние будет работать для вас, так как вы получили отдельную копию - ту, что вы получили от JSON, и сохраненную (поступающую из хранилища).Merge делает именно это - обновляет постоянное свойство значениями от отдельного, и если его нет, оно создает его (я не уверен, что эта часть будет желательной).Все еще делая это автоматически, вы теряете гибкость, которую вы имеете в написании этого самостоятельно.

В JPA метод слияния является частью EntityManager.Поэтому вам нужно будет ввести его и назвать как em.merge (detachedEntity);

Кроме этого, есть библиотеки для этого, но я их не использовал.И лучшее решение, которое требует некоторого кодирования, - это написать метод для обновления полей вручную;)

0 голосов
/ 29 июня 2018

Я обнаружил, что точное требование моего вопроса не может быть выполнено. Dozer Bean Mapper выглядело как опция, но это больше касается отображения объектов bean разных классов, где мы можем соответствовать отображаемым полям, что не в моем случае.

Решением было изменитьподход, при котором вся необходимая информация отправляется при выполнении обновления.

Как Саймон указал в комментарии:

Простой ответ: это невозможно.Потому что после десериализации, если поля отсутствуют, значение равно нулю.Java является типизированным статическим языком и не очень хорошо соответствует вашим требованиям.

0 голосов
/ 30 мая 2018

Взгляните на dozer - библиотеку сопоставления бинов.Вы можете настроить dozer с помощью специального сопоставителя полей, чтобы он не копировал поле, если оно пустое.

Вы можете извлечь объект из БД, скопировать значения поля из объекта запроса в объект, извлеченный из БД (с помощью специального сопоставителя полей, который не отображает нулевые значения), а затем сохраните объект.

    User user1 = new User(); // Request body
    user1.setFirstName("newFn");

    User user2 = new User(); // Entity retrieved from the database
    user2.setFirstName("fn");
    user2.setLastName("ln");

    DozerBeanMapper dozerBeanMapper = new DozerBeanMapper();
    dozerBeanMapper.setCustomFieldMapper(
            (source, destination, sourceFieldValue, classMap, fieldMapping) -> sourceFieldValue == null);
    dozerBeanMapper.map(user1, user2);
    System.out.println(user2); // User(firstName=newFn, lastName=ln)

Ссылка: https://stackoverflow.com/a/36716023/1377058

Если вы не хотите добавлять dozer в качестве зависимостиВы также можете использовать BeanUtils для копирования только тех свойств, которые не равны NULL.Посмотрите этот вопрос, чтобы узнать, как это сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...