Java Spring数据JPA与额外列的多个关系
我一直在努力与链接表中的一个附加列建立多对多关系 这些是我的实体:Java Spring数据JPA与额外列的多个关系,java,spring,hibernate,jpa,spring-data-jpa,Java,Spring,Hibernate,Jpa,Spring Data Jpa,我一直在努力与链接表中的一个附加列建立多对多关系 这些是我的实体: @JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" }) public class Post { @Id @GeneratedValue private Long id; private String name; @OneToMany(mappedBy = "post", cascade = C
@JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class Post {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
@JsonIgnore
private List<PostTag> tags = new ArrayList<>();
//getters and setters
public void addTag(Tag tag){
PostTag postTag = new PostTag(this, tag);
tags.add(postTag);
tag.getPosts().add(postTag);
}
public void removeTag(Tag tag) {
for (Iterator<PostTag> iterator = tags.iterator();
iterator.hasNext(); ) {
PostTag postTag = iterator.next();
if (postTag.getPost().equals(this) &&
postTag.getTag().equals(tag)) {
iterator.remove();
postTag.getTag().getPosts().remove(postTag);
postTag.setPost(null);
postTag.setTag(null);
}
}
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Post post = (Post) o;
return id == post.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
@JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class Tag {
@Id
@GeneratedValue
private Long id;
private String comment;
@OneToMany(mappedBy = "tag", cascade = CascadeType.ALL, orphanRemoval = true)
@JsonIgnore
private List<PostTag> posts = new ArrayList<>();
//getters and setters
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Tag that = (Tag) o;
return id == that.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
@Entity(name = "PostTag")
@Table(name = "post_tag")
@JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class PostTag {
@EmbeddedId
private PostTagId id;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("postId")
private Post post;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("tagId")
private Tag tag;
private Integer impact;
public FacilityParticipant(Post post, Tag tag) {
this.post = post;
this.tag = tag;
this.id = new PostTagId(post.getId(), tag.getId());
}
//getters and setters
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
PostTag that = (PostTag) o;
return Objects.equals(post, that.post) && Objects.equals(tag, that.tag);
}
@Override
public int hashCode() {
return Objects.hash(post, tag);
}
}
@Embeddable
public class PostTagId implements Serializable {
private Long postId;
private Long tagId;
//getters setters
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
PostTagId that = (PostTagId) o;
return Objects.equals(postId, that.postId) && Objects.equals(tagId, that.tagId);
}
@Override
public int hashCode() {
return Objects.hash(postId, tagId);
}
}
当尝试插入这些项目时,我得到一个错误,即我无法将NULL插入(“POST_标记“.ID”)
我尝试过的任何东西,要么会出现其他错误,要么会立即恢复
很可能模型中的某些东西不正确,但我真的不知道它有什么问题
整个建模基于本文
任何帮助都将不胜感激
谢谢spring数据jpa是jpa之上的一层。每个实体都有自己的存储库,您必须处理这个问题。我已经看过上面提到的教程,它是针对JPA的,它还将ID设置为null,这似乎有点不正确,可能是错误的原因。我看起来没那么近。为了处理SpringDataJPA中的问题,您需要一个单独的链接表存储库
@Entity
public class Post {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PostTag> tags;
@Entity
public class Tag {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "tag", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PostTag> posts;
@Entity
public class PostTag {
@EmbeddedId
private PostTagId id = new PostTagId();
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("postId")
private Post post;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("tagId")
private Tag tag;
public PostTag() {}
public PostTag(Post post, Tag tag) {
this.post = post;
this.tag = tag;
}
@SuppressWarnings("serial")
@Embeddable
public class PostTagId implements Serializable {
private Long postId;
private Long tagId;
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
PostTagId that = (PostTagId) o;
return Objects.equals(postId, that.postId) && Objects.equals(tagId, that.tagId);
}
@Override
public int hashCode() {
return Objects.hash(postId, tagId);
}
注意,几乎没有变化。我没有明确设置PostTagId
id。这些由持久层(本例中为hibernate)处理
还请注意,您可以使用自己的repo明确更新PostTag
条目,也可以从列表中添加和删除它们,因为CascadeType.ALL
已设置,如图所示。对spring数据jpa使用CascadeType.ALL
的问题在于,即使预取联接表实体,spring数据jpa仍会再次执行该操作。试图通过级联类型更新关系。新实体的所有都有问题
如果没有CascadeType
,posts
或tags
列表(应该设置)都不是关系的所有者,因此添加到它们就无法实现持久性,只能用于查询结果
在阅读PostTag
关系时,您需要专门获取它们,因为您没有FetchType.EAGER
。FetchType.EAGER
的问题是,如果您不想要连接,并且如果您将其同时放在Tag
和Post
上,那么您将创建一个递归的获取,该获取可以用于任何查询的所有标记和Posts
@Query("select t from Tag t left outer join fetch t.posts tps left outer join fetch tps.post where t.id = :id")
Tag getOneWithPosts(@Param("id") Long id);
最后,一定要检查日志。注意,创建关联需要SpringDataJPA(我认为jpa)读取现有表,以查看关系是新的还是更新的。无论您是自己创建并保存PostTag
,还是预取列表,都会发生这种情况。JPA有一个单独的合并,我认为你可以更有效地使用它
create table post (id bigint generated by default as identity, primary key (id))
create table post_tag (post_id bigint not null, tag_id bigint not null, primary key (post_id, tag_id))
create table tag (id bigint generated by default as identity, primary key (id))
alter table post_tag add constraint FKc2auetuvsec0k566l0eyvr9cs foreign key (post_id) references post
alter table post_tag add constraint FKac1wdchd2pnur3fl225obmlg0 foreign key (tag_id) references tag
Step 1
insert into tag (id) values (null)
insert into post (id) values (null)
select posttag0_.post_id as post_id1_1_0_, posttag0_.tag_id as tag_id2_1_0_ from post_tag posttag0_ where posttag0_.post_id=? and posttag0_.tag_id=?
insert into post_tag (post_id, tag_id) values (?, ?)
Step 2
insert into post (id) values (null)
insert into tag (id) values (null)
select posttag0_.post_id as post_id1_1_0_, posttag0_.tag_id as tag_id2_1_0_ from post_tag posttag0_ where posttag0_.post_id=? and posttag0_.tag_id=?
insert into post_tag (post_id, tag_id) values (?, ?)
Step 3
select tag0_.id as id1_2_0_, posts1_.post_id as post_id1_1_1_, posts1_.tag_id as tag_id2_1_1_, post2_.id as id1_0_2_, posts1_.tag_id as tag_id2_1_0__, posts1_.post_id as post_id1_1_0__ from tag tag0_ left outer join post_tag posts1_ on tag0_.id=posts1_.tag_id left outer join post post2_ on posts1_.post_id=post2_.id where tag0_.id=?
select tag0_.id as id1_2_1_, posts1_.tag_id as tag_id2_1_3_, posts1_.post_id as post_id1_1_3_, posts1_.post_id as post_id1_1_0_, posts1_.tag_id as tag_id2_1_0_ from tag tag0_ left outer join post_tag posts1_ on tag0_.id=posts1_.tag_id where tag0_.id=?
select posttag0_.post_id as post_id1_1_0_, posttag0_.tag_id as tag_id2_1_0_ from post_tag posttag0_ where posttag0_.post_id=? and posttag0_.tag_id=?
insert into post_tag (post_id, tag_id) values (?, ?)
Step 4 -- better
select posttag0_.post_id as post_id1_1_0_, posttag0_.tag_id as tag_id2_1_0_ from post_tag posttag0_ where posttag0_.post_id=? and posttag0_.tag_id=?
insert into post_tag (post_id, tag_id) values (?, ?)
可能您错过了PostTag实体上的@IdClass(PostTagId.class)?如果没有它,它应该可以工作。这里的最后一个解决方案是什么:仍然不工作:(
@Query("select t from Tag t left outer join fetch t.posts tps left outer join fetch tps.post where t.id = :id")
Tag getOneWithPosts(@Param("id") Long id);
create table post (id bigint generated by default as identity, primary key (id))
create table post_tag (post_id bigint not null, tag_id bigint not null, primary key (post_id, tag_id))
create table tag (id bigint generated by default as identity, primary key (id))
alter table post_tag add constraint FKc2auetuvsec0k566l0eyvr9cs foreign key (post_id) references post
alter table post_tag add constraint FKac1wdchd2pnur3fl225obmlg0 foreign key (tag_id) references tag
Step 1
insert into tag (id) values (null)
insert into post (id) values (null)
select posttag0_.post_id as post_id1_1_0_, posttag0_.tag_id as tag_id2_1_0_ from post_tag posttag0_ where posttag0_.post_id=? and posttag0_.tag_id=?
insert into post_tag (post_id, tag_id) values (?, ?)
Step 2
insert into post (id) values (null)
insert into tag (id) values (null)
select posttag0_.post_id as post_id1_1_0_, posttag0_.tag_id as tag_id2_1_0_ from post_tag posttag0_ where posttag0_.post_id=? and posttag0_.tag_id=?
insert into post_tag (post_id, tag_id) values (?, ?)
Step 3
select tag0_.id as id1_2_0_, posts1_.post_id as post_id1_1_1_, posts1_.tag_id as tag_id2_1_1_, post2_.id as id1_0_2_, posts1_.tag_id as tag_id2_1_0__, posts1_.post_id as post_id1_1_0__ from tag tag0_ left outer join post_tag posts1_ on tag0_.id=posts1_.tag_id left outer join post post2_ on posts1_.post_id=post2_.id where tag0_.id=?
select tag0_.id as id1_2_1_, posts1_.tag_id as tag_id2_1_3_, posts1_.post_id as post_id1_1_3_, posts1_.post_id as post_id1_1_0_, posts1_.tag_id as tag_id2_1_0_ from tag tag0_ left outer join post_tag posts1_ on tag0_.id=posts1_.tag_id where tag0_.id=?
select posttag0_.post_id as post_id1_1_0_, posttag0_.tag_id as tag_id2_1_0_ from post_tag posttag0_ where posttag0_.post_id=? and posttag0_.tag_id=?
insert into post_tag (post_id, tag_id) values (?, ?)
Step 4 -- better
select posttag0_.post_id as post_id1_1_0_, posttag0_.tag_id as tag_id2_1_0_ from post_tag posttag0_ where posttag0_.post_id=? and posttag0_.tag_id=?
insert into post_tag (post_id, tag_id) values (?, ?)