Spring-Data-Jpa очищает все параметры связанных сущностей после сохранения - PullRequest
0 голосов
/ 16 октября 2018

Я пытаюсь использовать JPA (с Hibernate), чтобы сохранить 2 объекта.Данные Spring предоставляют интерфейс, но я не думаю, что это имеет значение здесь.

У меня есть основная сущность под названием «Модель».Эта модель имеет много связанных объектов «Параметр».Я пишу метод для сохранения модели и ее параметров.

Это метод:

  private void cascadeSave(Model model) {

    modelRepository.save(model);

    for (ParameterValue value : model.getParameterValues()) {
        parameterValueRepository.save(value);
    }
}

Это проблема:

Когда я загружаю модельчто уже существовало до , добавьте в него некоторые новые параметры и затем вызовите этот метод для сохранения их обоих, что-то странное происходит:

Перед первым сохранением (modelRepository.save) это то, чтоДанные модели при отладке выглядят так:

enter image description here

Модель имеет 2 параметра с заполненными значениями (имя и модель заполнены).

Теперь, после сохранения модели первого сохранения в моем методе, это происходит.Обратите внимание, что ссылка на объект является другой, поэтому Hibernate должен был сделать что-то волшебное и воссоздать значения, а не оставлять их в покое:

enter image description here

Почему-тоhibernate очистил все атрибуты параметров в наборе.

Теперь, когда сохранение нового параметра происходит в следующем коде, происходит сбой из-за ненулевых ограничений и т. д.

Мой вопрос: почемуhibernate очищает все поля?

Вот соответствующие сопоставления:

ParameterValue

@Entity
@Table(name = "tbl_parameter_value")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "PARAMETER_TYPE")
public abstract class ParameterValue extends AbstractBaseObject {

    @Column(nullable = false)
    @NotBlank
    private String name;
    private String stringValue;
    private Double doubleValue;
    private Integer intValue;
    private Boolean booleanValue;
    @Enumerated(EnumType.STRING)
    private ModelType modelParameterType;
    @Column(precision = 7, scale = 6)
    private BigDecimal bigDecimalValue;
    @Lob
    private byte[] blobValue;

    ParameterValue() {
    }

    ParameterValue(String name) {
        this.name = name;
    }

ModelParameterValue

@Entity
@DiscriminatorValue(value = "MODEL")
public class ModelParameterValue extends ParameterValue {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "model_id", foreignKey = @ForeignKey(name = "FK_VALUE_MODEL"))
    private Model model;

    ModelParameterValue() {
        super();
    }

    ModelParameterValue(String name) {
        super(name);
    }

Модель

@Entity
@Table(name = "tbl_model")
public class Model extends AbstractBaseObject implements Auditable {

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "model")
    private Set<ModelParameterValue> parameterValues = new HashSet<>();

РЕДАКТИРОВАТЬ

Мне удалось воспроизвести это на минимальном примере.Если вы замените все данные Spring, то это то, что произошло под капотом (например, JPA EntityManager):

public Model simpleTest() {

    Model model = new Model("My Test Model");
    em.persist(model);

    model.addParameter(new Parameter("Param 1"));
    em.merge(model);

    for (Parameter child : model.getParameters()) {
        em.persist(child);
    }

    return model;
}

При выполнении слияния все атрибуты параметров устанавливаются в ноль.На самом деле они просто заменены совершенно новыми параметрами.

1 Ответ

0 голосов
/ 16 октября 2018

Полагаю, вы используете Spring Data Jpa в качестве репозитория model.Это указывает на следующие последствия.

Spring Repository Save

S save (S entity)

Сохраняет данныеюридическое лицо.Используйте возвращенный экземпляр для дальнейших операций, так как операция сохранения могла бы полностью изменить экземпляр сущности.

Так что это нормальное поведение, с которым вы столкнулись.

Код должен быть изменен на:

model = modelRepository.save(model);

for (ParameterValue value : model.getParameterValues()) {
    parameterValueRepository.save(value);
}

РЕДАКТИРОВАТЬ:

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

Cascade

Cascade работает так: «Если вы сохраняете Parent, сохраняете Children, если вы обновляете Parent, обновляете Children... "

Таким образом, мы можем поставить каскад на ваше отношение следующим образом:

@Entity
@Table(name = "tbl_model")
public class Model extends AbstractBaseObject implements Auditable {

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "model", cascade = CascadeType.ALL)
    private Set<ModelParameterValue> parameterValues = new HashSet<>();

, а затем сохранить только так

  private void cascadeSave(Model model) {

    modelRepository.save(model);
    //ParamValues will be saved/updated automaticlly if your model has changed

}

Вниз-вверх сохранить

Второй вариант - сначала сохранить параметры, а затем моделировать их.

  private void cascadeSave(Model model) {

    model.setParameterValues(
      model.getParameterValues().stream()
       .map(param ->  parameterValueRepository.save(param))
       .collect(Collectors.toSet())
   );
    modelRepository.save(model);
}

Я не проверял второй код в моем компиляторе, но идея состоит в том, чтобы сначала сохранить дочерние элементы (ParamValues), поставитьэто в модель, а затем сохранить модель:)

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