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;
问题可以在SimpleJpaRepository
save()
方法中找到
@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<>();
我有 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;
问题可以在SimpleJpaRepository
save()
方法中找到
@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<>();