为什么 Hibernate 会为与 @JoinTable 的双向 @OneToMany 关系生成复杂的子查询?

问题描述 投票:0回答:1

我正在使用 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 为这个设置生成的附加连接子查询是否正常,如果是,为什么会发生?

database spring-boot hibernate jpa orm
1个回答
0
投票

看来你的方法不正确。

如果您需要使用双向 @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 映射的更复杂的实现,例如还需要涉及附加列,那么需要为其创建单独的实体类

© www.soinside.com 2019 - 2024. All rights reserved.