我正在使用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实体通过使用名为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为该设置生成的附加连接子查询正常吗?如果是,为什么会发生这种情况?

推荐答案

看来你的方法是不正确的.

如果您需要使用BIRECTIONAL@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映射的实现,如附加列也需要涉及,则需要为其创建单独的实体类

Database相关问答推荐

包含接受Cassandra中多个数据的语句

使用Postgres获取带有表架构的外键

Pocketbase 中的 SQLite 数据库可以根据自己的喜好进行修改吗?

postgres 索引扫描的启动成本(postgresql 书的内部 struct )

如何决定使用数据库事务

一个强大的 MySQL 管理工具,具有与 SQL Server Management Studio 类似的功能

PostgreSQL 嵌套 INSERTs / WITHs 用于外键插入

如何以编程方式在 C# 中创建 Microsoft Access 数据库?

预测下一个自动插入的行 ID (SQLite)

是否可以在ORDER BY子句之后放置任何可能造成安全风险的内容?

Sitecore - 将项目从 Web 移动到 Master?

审计表:一个表或一个表的每个字段

mySQL 复制是否具有即时数据一致性?

删除 PHP 中的所有小数

在单个 postgres 查询中多次调用 `now()` 是否总是给出相同的结果?

你可以在一个 Hibernate Session 中有多个事务吗?

在 SQL Server 中实施审计表的建议?

MongoDB 是否支持浮点类型?

数据库效率 - 每个用户的表与用户表

数据库事务是否防止竞争条件?