查询多对多连接时 Jpa 休眠问题 table
Jpa hibernate problem while querying many to many join table
我在 POST 和 TAG 之间建立了多对多关系。每个post可以有多个标签,每个标签可以有多个post。
我想管理与映射到连接 table 的实体的关系。所以我有 3 个实体 类:Post
、Tag
、PostTag
。 PostTag
有 @ManyToOne
注释 Post
和 Tag
成员。
PostTag
及其嵌入密钥:
@Entity
@Table(name = "post_tag")
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 PostTag() {}
public PostTag(Post post, Tag tag) {
this.post = post;
this.tag = tag;
this.id = new PostTagId(post.getId(), tag.getId());
}
public PostTagId getId() { return id; }
public void setId(PostTagId id) { this.id = id; }
public Post getPost() { return post; }
public void setPost(Post post) { this.post = post; }
public Tag getTag() { return tag; }
public void setTag(Tag tag) { this.tag = tag; }
}
@Embeddable
public class PostTagId implements Serializable {
@Column(name = "post_id")
private Long postId;
@Column(name = "tag_id")
private Long tagId;
public PostTagId() {}
public PostTagId(Long postId, Long tagId) {
this.postId = postId;
this.tagId = tagId;
}
public Long getPostId() { return postId; }
public void setPostId(Long postId) { this.postId = postId; }
public Long getTagId() { return tagId; }
public void setTagId(Long tagId) { this.tagId = tagId; }
}
当我需要具有给定标签的帖子时,我想使用此查询:
@Query(value = "select pt from PostTag pt join fetch pt.post where pt.id.tagId = :tagId")
Set<PostTag> findByTagIdAndFetchPosts(@Param("tagId") Long tagId);
问题是 Hibernate 创建了这个 select:
2020-08-25 10:21:57.486 DEBUG 16791 --- [ main] org.hibernate.SQL :
select
posttag0_.post_id as post_id1_1_0_,
posttag0_.tag_tag_id as tag_tag_2_1_0_
from
post_tag posttag0_
where
posttag0_.post_id=?
and posttag0_.tag_tag_id=?
导致以下错误:
2020-08-25 10:21:57.487 WARN 16791 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 42122, SQLState: 42S22
2020-08-25 10:21:57.487 ERROR 16791 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Column "POSTTAG0_.TAG_TAG_ID" not found; SQL statement:
select posttag0_.post_id as post_id1_1_0_, posttag0_.tag_tag_id as tag_tag_2_1_0_ from post_tag posttag0_ where posttag0_.post_id=? and posttag0_.tag_tag_id=? [42122-200]
怎么了?
全部内容在这里:
https://github.com/riskop/jpa_hibernate_spring_boot_many_to_many_managed_on_join_table_problem
当你使用@MapsId
时,hibernate实际上忽略了@Embeddable
class的适当字段的@Column
注释中提供的列名,并开始使用该名称来自 @JoinColumn
。如果 @JoinColumn
不存在,则应用默认约定(引用关系名称的串联 属性;“_”;引用的主键列的名称)。
你有:
@Entity
public class Tag {
@Id
@Column(name="TAG_ID")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// ...
}
@Entity
@Table(name = "post_tag")
public class PostTag {
@EmbeddedId
private PostTagId id;
// There is no @JoinColumn annotation !!!
// So, the default naming convention is used
// "tag" + "_" + "tag_id"
// "tag_id" is the Tag's entity PK column name
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("tagId")
private Tag tag;
// ...
}
因此,您可以通过这种方式修复映射:
@Entity
@Table(name = "post_tag")
public class PostTag {
@EmbeddedId
private PostTagId id;
// by chance the default naming convention
// lead to the same column name for this case
@MapsId("postId")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id")
private Post post;
@MapsId("tagId")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "tag_id")
private Tag tag;
// ...
}
并且您可以从 PostTagId
字段中删除 @Column
注释:
@Embeddable
public class PostTagId implements Serializable {
private Long postId;
private Long tagId;
// ...
}
因为它们被忽略了。
我在 POST 和 TAG 之间建立了多对多关系。每个post可以有多个标签,每个标签可以有多个post。
我想管理与映射到连接 table 的实体的关系。所以我有 3 个实体 类:Post
、Tag
、PostTag
。 PostTag
有 @ManyToOne
注释 Post
和 Tag
成员。
PostTag
及其嵌入密钥:
@Entity
@Table(name = "post_tag")
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 PostTag() {}
public PostTag(Post post, Tag tag) {
this.post = post;
this.tag = tag;
this.id = new PostTagId(post.getId(), tag.getId());
}
public PostTagId getId() { return id; }
public void setId(PostTagId id) { this.id = id; }
public Post getPost() { return post; }
public void setPost(Post post) { this.post = post; }
public Tag getTag() { return tag; }
public void setTag(Tag tag) { this.tag = tag; }
}
@Embeddable
public class PostTagId implements Serializable {
@Column(name = "post_id")
private Long postId;
@Column(name = "tag_id")
private Long tagId;
public PostTagId() {}
public PostTagId(Long postId, Long tagId) {
this.postId = postId;
this.tagId = tagId;
}
public Long getPostId() { return postId; }
public void setPostId(Long postId) { this.postId = postId; }
public Long getTagId() { return tagId; }
public void setTagId(Long tagId) { this.tagId = tagId; }
}
当我需要具有给定标签的帖子时,我想使用此查询:
@Query(value = "select pt from PostTag pt join fetch pt.post where pt.id.tagId = :tagId")
Set<PostTag> findByTagIdAndFetchPosts(@Param("tagId") Long tagId);
问题是 Hibernate 创建了这个 select:
2020-08-25 10:21:57.486 DEBUG 16791 --- [ main] org.hibernate.SQL :
select
posttag0_.post_id as post_id1_1_0_,
posttag0_.tag_tag_id as tag_tag_2_1_0_
from
post_tag posttag0_
where
posttag0_.post_id=?
and posttag0_.tag_tag_id=?
导致以下错误:
2020-08-25 10:21:57.487 WARN 16791 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 42122, SQLState: 42S22
2020-08-25 10:21:57.487 ERROR 16791 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Column "POSTTAG0_.TAG_TAG_ID" not found; SQL statement:
select posttag0_.post_id as post_id1_1_0_, posttag0_.tag_tag_id as tag_tag_2_1_0_ from post_tag posttag0_ where posttag0_.post_id=? and posttag0_.tag_tag_id=? [42122-200]
怎么了?
全部内容在这里:
https://github.com/riskop/jpa_hibernate_spring_boot_many_to_many_managed_on_join_table_problem
当你使用@MapsId
时,hibernate实际上忽略了@Embeddable
class的适当字段的@Column
注释中提供的列名,并开始使用该名称来自 @JoinColumn
。如果 @JoinColumn
不存在,则应用默认约定(引用关系名称的串联 属性;“_”;引用的主键列的名称)。
你有:
@Entity
public class Tag {
@Id
@Column(name="TAG_ID")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// ...
}
@Entity
@Table(name = "post_tag")
public class PostTag {
@EmbeddedId
private PostTagId id;
// There is no @JoinColumn annotation !!!
// So, the default naming convention is used
// "tag" + "_" + "tag_id"
// "tag_id" is the Tag's entity PK column name
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("tagId")
private Tag tag;
// ...
}
因此,您可以通过这种方式修复映射:
@Entity
@Table(name = "post_tag")
public class PostTag {
@EmbeddedId
private PostTagId id;
// by chance the default naming convention
// lead to the same column name for this case
@MapsId("postId")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id")
private Post post;
@MapsId("tagId")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "tag_id")
private Tag tag;
// ...
}
并且您可以从 PostTagId
字段中删除 @Column
注释:
@Embeddable
public class PostTagId implements Serializable {
private Long postId;
private Long tagId;
// ...
}
因为它们被忽略了。