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



我有两个实体的关系为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表中生成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;

... 
}

现在,保存帖子后,savedPost对象不再包含注释(实际上它包含一个所有字段为null的Comment(。连接似乎断了。

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


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

如果不是.save(post),而是调用.saveAndFlush(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时,它不会被认为是新的,因此不会调用EntityManger.persist(),而是调用EntityManager.merge()

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

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

最新更新