Почему идентификатор генерируется для локальной переменной только тогда, когда перед сохранением производится сброс? - PullRequest
0 голосов
/ 20 декабря 2018

Допустим, у меня есть три класса.

public class Parent {
    @Id
    @GeneratedValue
    @Column(name = "parent_id", updatable = false, insertable = false)
    private Long id;

    private String name;

    @Builder.Default
    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
    Set<Child> childs = new HashSet<>();
}

public class Child {
    @Id
    @GeneratedValue
    @Column(name = "child_id", updatable = false, insertable = false)
    private Long id;

    private String name;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name ="parent_id")
    Parent parent;

    @Builder.Default
    @OneToMany(mappedBy = "child", cascade = CascadeType.ALL)
    Set<GrandChild> grandChildren = new HashSet<>();
}

public class GrandChild {
    @Id
    @GeneratedValue
    @Column(name = "grandchildid", updatable = false, insertable = false)
    private Long id;

    private String name;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "child_id")
    Child child;
}

Если я создам новый GrandChild grandChild с помощью parent.getChilds().get(0).getGranChilds().add(grandChild) и сохраню сущность с помощью parentRepo.save(parent).Локальная переменная grandChild не будет иметь id.Но если я сначала сброшу, а затем сохраню, локальная переменная будет иметь идентификатор?Это то, что вы обычно делаете?

Я думал, что это произойдет, когда вы сохраните, а затем сбросите.Но, похоже, работает только тогда, когда я ПЕРВЫЙ сброс, а затем сохранить.

Добавление grandChild:

   GrandChild grandChild = GrandChild.builder().name(name).build();
   Parent parent = parentRepo.findAll().get(0);

   Optional<Child> optional = parent.getChilds().stream().findAny();

   optional.ifPresent(child -> child.getGrandChildren().add(grandChild));

(Это всего лишь код для примера, так что не обращайте внимания на уродство).

Сохранение с очисткой после (без идентификатора, сгенерированного для локальной переменной, объект все еще сохраняется):

parentRepo.saveAndFlush(parent);
System.out.println(grindChild.getId()); // null

Сброс до (локальная переменная получает идентификатор):

parentRepo.flush();
parentRepo.save(parent);
System.out.println(grandChild.getId()); //not null, value exists

Идентификатор в обоих случаях генерируется в базе данных.

Ответы [ 2 ]

0 голосов
/ 21 декабря 2018

Проблема здесь заключалась в том, что различные каскады выполнялись в зависимости от того, была ли сделана очистка до или после сохранения.

Если выполнить очистку перед сохранением, сущность будет сохранена с помощью каскада ACTION_PERSIST_ON_FLUSH, который использует ту же ссылку на объект, что и локальную переменную.

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

В обоих случаях saveWithGeneratedId(...) был вызван в org.hibernate.event.internal.AbstractSaveEventListener классе.Просто с разными ссылками на объекты.

0 голосов
/ 21 декабря 2018

Я предполагаю, что вы можете сохранить экземпляр, не сбрасывая и не присваивая результат локальной переменной.Пожалуйста, смотрите следующий комментарий javadoc из CrudRepository интерфейса:

/**
 * Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
 * entity instance completely.
 *
 * @param entity must not be {@literal null}.
 * @return the saved entity will never be {@literal null}.
 */
<S extends T> S save(S entity);

Я думаю, вы можете попробовать следующий подход:

Parent persistentParent = parentRepo.saveAndFlush(parent);

Где persistentParent должен иметь сгенерированное значение Id доступным.

UPD

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

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