多对多注释未在选择查询中生成连接

Posted

技术标签:

【中文标题】多对多注释未在选择查询中生成连接【英文标题】:ManyToMany annotations not generating join in select query 【发布时间】:2019-08-19 08:50:48 【问题描述】:

总结: 我正在尝试使用 jpa + hibernate 建立并急切地检索单向多对多关系。

在做findAll()时,引用的实体是空的,应该有1个。

hibernate 生成的 SQL(使用 show-sql 属性)缺少我所看到的连接。

上下文

Spring 数据 - 4.0.4.RELEASE 休眠 - 4.2.21.Final

我尝试过的一些替代方案/修复:

已尝试将它们切换为 OneToMany/ManyToOne 关系。 已尝试通过使用 mappedBy 引用来自 Student 的 Class 来设置双向多对多关系 已尝试将 Class 的 id 列更新为在连接表中不存在差异

Java 实体

@Data
@Entity
@Table(name = "student")
public class Student 

@Column(name = "student_id", unique = true, nullable = false)
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
@Data
@Entity
@Table(name = "Class")
public class Class 

@Column(name = "id", unique = true, nullable = false)
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

@ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
        name = "class_student",
        joinColumns = @JoinColumn(name = "class_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "student_id", referencedColumnName = "student_id"))
    private Set<Student> students;

DDL

CREATE TABLE IF NOT EXISTS `student` (
    student_id INT NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (`student_id `)
);

CREATE TABLE IF NOT EXISTS `class` (
    `id` INT NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (`id`)
);

CREATE TABLE IF NOT EXISTS `class_student ` (
    student_id INT NOT NULL,
    class_id INT NOT NULL,
    PRIMARY KEY (`student_id `, `class_id`),
    CONSTRAINT `fk_student_id` FOREIGN KEY (`student_id`) REFERENCES `student` (`student_id`),
    CONSTRAINT `fk_class_id` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`)
);

实际与预期: 当我classRespository.getAll() 时实际生成的 sql 似乎缺少我所期望的 class + class_student 之间的连接。

它还奇怪地包括了 student 和 class_student 之间的连接,这是我没想到的,因为它是单向定义的,而且除了可能被丢弃之外,我不知道对该意外查询的结果做了什么。

实际生成的 SQL

Hibernate: 
    select
        classin0_.id as id1_29_,
    from
        class classin0_
    INNER JOIN
       post_tag pt
    ON     p.id = pt.post_id
    INNER JOIN
        tag t
    ON     pt.tag_id = t.id
    WHERE  p.id = 1
Hibernate: 
    select
        class_student0_.class_id as id1_30_1_,
        class_student0_.student_id as featured2_10_1_,
        student1_.student_id as featured1_28_0_,
    from
        class_student class_student0_ 
    inner join
        student student1_ 
            on class_student0_.student_id=student1_.student_id 
    where
        class_student0_.id=?

我希望 jpa 可以在三个表中进行内部连接的查询可以解析回一个集合。

任何帮助将不胜感激。

【问题讨论】:

仅供参考,急切地获取 ManyToMany 通常是个坏主意,因为返回的数据可能会导致大量重复。 附注 - 不要命名类Class,想出类似Lecture 之类的东西。否则可能会导致很多问题。 @sp00m 那么将其视为ManyToOne会更好吗? @Amongalen 哦同意了,只是这个问题的(糟糕的)临时名称,它不是学生 - 现实中的班级关系 【参考方案1】:

我检查了你的映射——它是正确的。我正在使用这些类。

@Entity
@Table(name = "student")
public class Student 

    @Column(name = "student_id", unique = true, nullable = false)
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "name")
    private String name;



@Entity
@Table(name = "Class")
public class Class 

    @Column(name = "id", unique = true, nullable = false)
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "className")
    private String className;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
            name = "class_student",
            joinColumns = @JoinColumn(name = "class_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "student_id", referencedColumnName = "student_id"))
    private Set<Student> students;


当我 classRespository.getAll() 时实际生成的 sql 似乎缺少我期望的 class + class_student 之间的连接。奇怪的是,它还包含了我没想到的 student 和 class_student 之间的连接

Hibernate 不对 classclass_student 关系使用连接。

Hibernate 通过第一次查询获取所有类

select
    class0_.id as id1_0_,
    class0_.className as classNam2_0_ 
from
    Class class0_

然后在class_studentstudent 之间使用inner join 让现有班级的所有学生。

   select
        students0_.class_id as class_id1_1_0_,
        students0_.student_id as student_2_1_0_,
        student1_.student_id as student_1_2_1_,
        student1_.name as name2_2_1_ 
    from
        class_student students0_ 
    inner join
        student student1_ 
            on students0_.student_id=student1_.student_id 
    where
        students0_.class_id=?

我无法检查您的 SQL,因为它不正确。 例如class_student表中没有class_student0_.id=?这样的字段。

【讨论】:

抱歉,连接表中的id 应该是class_id @GavinFitzgerald 最好提供真正的 SQL 或使用 ClassStudent 实体进行测试。

以上是关于多对多注释未在选择查询中生成连接的主要内容,如果未能解决你的问题,请参考以下文章

hibernate关联关系(多对多)

hibernate多对多查询

针对标签上的多对多连接优化 MySQL 查询

MySQL 基础 -- 多表关系(一对一1对多(多对一)多对多)多表查询(内连接外连接自连接子查询(嵌套查询)联合查询 union)笛卡儿积

仅从 Spring Data JPA 中的联接表(多对多)中选择特定列

多对多无连接表