我正在使用 Spring Boot 和 Hibernate,管理具有通过中间表连接的双向 @OneToMany 关系的实体。这是我的实体定义:
@Entity
@Table(name = "feedback")
@NamedEntityGraph(name = "full", includeAllAttributes = true)
@Getter
@Setter
@SequenceGenerator(allocationSize = 1, name = "feedback_seq_gen", sequenceName = "feedback_seq")
public class Feedback {
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "feedback_seq_gen")
private Long id;
@Column(name = "text", length = Integer.MAX_VALUE)
private String text;
@OneToMany(mappedBy = "feedback", fetch = FetchType.LAZY)
private Set<Image> images = new HashSet<>();
}
@Entity
@Table(name = "image")
@Getter
@Setter
@SequenceGenerator(allocationSize = 1, name = "image_seq_gen", sequenceName = "image_seq")
public class Image {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "image_seq_gen")
@Column(name = "id", nullable = false)
private Long id;
@Column(name = "url", length = Integer.MAX_VALUE)
private String url;
@ManyToOne(fetch = FetchType.LAZY)
@JoinTable(name = "feedback_image",
inverseJoinColumns = @JoinColumn(name = "feedback_id"),
joinColumns = @JoinColumn(name = "image_id"))
private Feedback feedback;
public void setFeedback(Feedback feedback) {
feedback.getImages().add(this);
this.feedback = feedback;
}
}
反馈和图像实体通过使用名为
feedback_image
的 @JoinTable 的 @OneToMany 关系进行关联。我使用联结表的原因是因为我需要在创建反馈之前上传图像。
存储库:
public interface FeedbackRepository extends JpaRepository<Feedback, Long> {
@EntityGraph("full")
@Query("select f from Feedback f where f.id = :id")
Optional<Feedback> getFullFeedbackById(Long id);
}
在测试关系和获取逻辑时,Hibernate 会生成一个复杂的 SQL 查询,其中包括子查询上的附加联接:
SELECT f1_0.id, i1_0.feedback_id, i1_1.id, i1_1.url, f1_0.text
FROM feedback f1_0
LEFT JOIN feedback_image i1_0 ON f1_0.id = i1_0.feedback_id
LEFT JOIN (image i1_1 LEFT JOIN feedback_image i1_2 ON i1_1.id = i1_2.image_id) ON i1_1.id = i1_0.image_id
WHERE f1_0.id = ?;
但是,我注意到,如果我将关系切换为@ManyToMany,Hibernate 会生成一个更简单、更直接的查询:
SELECT f1_0.id, i1_0.feedback_id, i1_1.id, i1_1.url, f1_0.text
FROM feedback f1_0
LEFT JOIN feedback_image i1_0 ON f1_0.id = i1_0.feedback_id
LEFT JOIN image i1_1 ON i1_1.id = i1_0.image_id
WHERE f1_0.id = ?;
但是这种方法与我的概念模型不符。
所以,我的问题是:Hibernate 为这个设置生成的附加连接子查询是否正常,如果是,为什么会发生?
看来你的方法不正确。
如果您需要使用双向 @OneToMany 映射这两个实体,这就是方法。
@Entity
@Table(name = "feedback")
@NamedEntityGraph(name = "full", includeAllAttributes = true)
@Getter
@Setter
@SequenceGenerator(allocationSize = 1, name = "feedback_seq_gen", sequenceName = "feedback_seq")
public class Feedback {
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "feedback_seq_gen")
private Long id;
@Column(name = "text", length = Integer.MAX_VALUE)
private String text;
@ManyToOne(mappedBy = "feedback", fetch = FetchType.LAZY)
@JoinColumn(name="IMAGE_ID")
private Image image;
}
@Entity
@Table(name = "image")
@Getter
@Setter
@SequenceGenerator(allocationSize = 1, name = "image_seq_gen", sequenceName = "image_seq")
public class Image {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "image_seq_gen")
@Column(name = "id", nullable = false)
private Long id;
@Column(name = "url", length = Integer.MAX_VALUE)
private String url;
@OneToMany(fetch = FetchType.LAZY,mappedBy="image",cascade=CascadeType.ALL)
private List<Feedback> feedback = new ArrayList<>();
public void setFeedback(Feedback feedback) {
feedback.getImages().add(this);
this.feedback = feedback;
}
}
所以,不需要使用连接表,
如果您有 @ManyToMany 关系并且仅使用两个表 id 进行映射,您可以使用下面的
@JoinTable(name = "feedback_image",
inverseJoinColumns = @JoinColumn(name = "feedback_id"),
joinColumns = @JoinColumn(name = "image_id"))
但是对于使用 @ManyToMany 映射的更复杂的实现,例如还需要涉及附加列,那么需要为其创建单独的实体类