Однонаправленный @OneToMany не работает должным образом с @EmbeddedId - PullRequest
0 голосов
/ 13 июня 2019

Если я использую этот кусок кода (CASE 1 на рисунке):

@Data
@Entity
public class PostOneUni {

    @EmbeddedId //if @Id, class CompositeId must be annotated @Embeddable?
    private CompositeId id;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumns({
            @JoinColumn(name = "id1"),
            @JoinColumn(name = "id2")
    })
    private Set<PostCommentUniMany> comments = new HashSet<>();

    ...
}

и при выполнении создания этого объекта и добавлении дочерних комментариев, при сохранении в БД все работает как ожидалось (идентификаторы на дочернихPostCommentUniMany добавляются как положено), но изменения не распространяются на код Java (объект @12081 на рисунке должен иметь поле id, обновленное до 2, а не null).

В другом случае(ПРИМЕР 2) Я использую этот код:

@Data
@Entity
public class PostOneUni {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "post_id")
    private Set<PostCommentUniMany> comments = new HashSet<>();

    ...
}

, и, как видно из рисунка, поля также сохраняются в БД, а объект, который использовался для сохранения состояния в БД, обновляется после сохранения (Объект @12052 обновлен, чтобы отразить id поле, которое будет 2 - как в БД).

enter image description here

Как обновить объект @12081 в случае 1, чтобы отразить идентификатор БД?

ОБНОВЛЕНИЕ

После обсуждения ниже - проблема заключалась в том, что если id для объекта вручную установить какое-либо значение, Spring думаетэто не новая сущность, и она пытается объединить, а не сохранять сущность.

Один из "worka"rounds "- установить @Version поле в @Entity class PostOneUni, которое будет отслеживать, является ли объект новым или нет.

@Version
private Integer version;

1 Ответ

1 голос
/ 13 июня 2019

Проблема в том, что, поскольку вы установили поля идентификаторов вручную, Spring Data вызывает операцию слияния, а не сохраняется:

См. Org.springframework.data.jpa.repository.support.SimpleJpaRepository

@Transactional
public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) //checks if ID null {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

И спецификация JPA отмечает, что когда

3.2.7.1 Слияние состояния отдельного объекта

• Если X - это новый экземпляр объекта, новыйЭкземпляр управляемого объекта X 'создается, и состояние X копируется в новый экземпляр управляемого объекта X'.

В тестовом коде, если вы, следовательно, выполните:

post = oneToManyService.addNewPost(post);

идентификаторы установлены правильно на возвращаемом экземпляре так же, как и при перезагрузке из базы данных.Однако исходные экземпляры (в «новом» состоянии) остаются неизменными, т.е. не имеют установленных идентификаторов.

Если для слияния вызывается persist, а не merge, то возвращается исходный (тот же) экземпляр, и идентификаторы будут правильно установлены в этом экземпляре.

...