单向@OneToMany 不能按预期使用@EmbeddedId

Unidirectional @OneToMany does not work as expected with @EmbeddedId

如果我使用这段代码(图中的案例 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 上的 ID 按预期添加)但更改不会传播到 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<>();

    ...
}

从图中可以看出,字段也被持久化到DB,保存后更新了用于保存状态到DB的对象(对象@12052被更新以反映id 字段为 2 - 与在 DB 中一样)。

如何更新案例 1 中的对象 @12081 以反映 DB id?

更新

经过下面的讨论 - 问题是如果手动将实体上的 id 设置为某个值,Spring 认为它不是新实体并尝试合并而不是保留实体。

"workarounds" 之一是在 @Entity class PostOneUni 上设置 @Version 字段,它将跟踪实体是否是新的。

@Version
private Integer version;

问题是因为您手动设置了 ID 字段 Spring 数据调用合并操作而不是持久化:

见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 Merging Detached Entity State

• If X is a new entity instance, a new managed entity instance X' is created and the state of X is copied into the new managed entity instance X'.

在你的测试代码中,如果你这样做:

post = oneToManyService.addNewPost(post);

标识符在返回的实例上正确设置,就像从数据库重新加载时一样。但是,原始实例(处于 'new' 状态)保持不变,即没有设置 ID。

在调用 persist 而不是 merge 的情况下,将返回原始(相同)实例,并将在此实例上正确设置标识符。