JPA - 当 @GenerateValue 不存在时 ManyToOne 中断

JPA - ManyToOne breaks when @GenerateValue is not present

我有 2 个具有 OneToMany 关系的实体

@Entity
class Post {    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", insertable = false, updatable = false)
    private Long id;

    @OneToMany(mappedBy = "post", fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
    Set<Comment> comments = new HashSet();

    public void addComment(Comment c) {
        c.setPost(this);
        comments.add(c);
    }
}

@Entity
class Comment {    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", insertable = false, updatable = false)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "post_id")
    private Post post;
}

CREATE TABLE post(
    id BIGINT NOT NULL DEFAULT nextval('post_id_seq') PRIMARY KEY,
    title VARCHAR(50)
);

CREATE TABLE comment (
    id BIGINT NOT NULL PRIMARY KEY,
    post_id BIGINT NOT NULL, 
    text VARCHAR(255),
    CONSTRAINT fk_comment_post_id
      FOREIGN KEY (post_id)
      REFERENCES post (id)
);

保存此实体时一切正常,savedPost 是包含评论的完整实体。

Post post = new Post();
post.setId(1L);
post.setTitle("Hello post test");
post.addComment(new Comment("Hi There");
Post savedPost = postRepository.save(post);

但是,从我决定删除该序列以在 Post table 中生成 Post Id 并删除注释 @GenerateValue 并将 id 设置为我生成的数字,事情开始下降

CREATE TABLE post(
    id BIGINT NOT NULL PRIMARY KEY,
    title VARCHAR(50)
);

@Entity
class Post {    
    @Id
    @Column(name = "id", updatable = false)
    private Long id;
    
    ... 
}

保存 post 后 savedPost 对象不再包含评论(实际上它包含一个所有字段都为空的评论)。看来连接坏了。

知道它发生在哪里以及为什么发生吗?


UPDATE 基于 Simon Martinelli 的代码:github.com/simasch/69978943

如果我调用 .saveAndFlush(post) 评论 returns 而不是 .save(post) 且仅设置了其 ID,则其余字段将为空。它比我描述的行为要好,但仍然不好。

但是如果我用 @GeneratedValue 注释 Post.id 并使用 .save(post),一切都会完美无缺。

@Entity
public class Post {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false)
    private Long id;

问题可以在SimpleJpaRepositorysave()方法中找到

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

    Assert.notNull(entity, "Entity must not be null.");

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

它正在检查实体是否是新的。但是,当您手动设置 ID 时,它不会被视为新 ID,因此不会调用 EntityManger.persist(),而是调用 EntityManager.merge()

因此您需要将 CascadeType.MERGE 添加到映射

@OneToMany(mappedBy = "post", fetch = FetchType.EAGER, 
           cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private Set<Comment> comments = new HashSet<>();