jpa 多表关联,头痛,求大佬指点

2021-02-09 12:05:35 +08:00
 NoKey

之前用的 mybatis,各种查询都是自己写,非常快捷

最近开始练习使用 jpa

涉及到多表关联,用起来有点头痛

我写了一个 demo,涉及 3 张表,学生,老师,学生-老师关联表

Student

@Entity
@Table
@Data
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(length = 32)
    private String name;

    @JoinTable(name = "student_and_teacher",
            joinColumns = {@JoinColumn(name = "studentId", referencedColumnName = "id")},
            inverseJoinColumns = {@JoinColumn(name = "teacherId", referencedColumnName = "id")},
            foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT),
            inverseForeignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT))
    @ManyToMany
    private List<Teacher> teachers;



}

其中的 @JoinTable 就是表明要关联到学生-老师关联表中去

Teacher 类

@Entity
@Table
@Data
public class Teacher {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(length = 32)
    private String name;


}

然后就是学生-老师关联

student-teacher

@Entity
@Table(name = "teacher_and_lesson")
@Data
public class StudentAndTeacher {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private Long studentId;

    @Column
    private Long teacherId;
}

这一套工作的很好,可以查询出学生-老师关系,添加一些数据后,执行查询学生的方法,可以得到

{"id":1,"name":"Joe","teachers":[{"id":1,"name":"王老师"},{"id":2,"name":"李老师"}]}

但是,这个时候,我想增加一个 课程表,设定每个老师教一个课程

Lesson

@Entity
@Table
@Data
public class Lesson {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(length = 32)
    private String name;
}

然后,就是增加老师-课程关联关系

TeacherAndLesson

@Entity
@Table
@Data
public class TeacherAndLesson {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private Long lessonId;

    @Column
    private Long teacherId;
}

这样的话,就需要在老师实体类中,增加一个课程的关联关系


@Entity
@Table
@Data
public class Teacher {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(length = 32)
    private String name;

    @JoinTable(name = "teacher_and_lesson",
            joinColumns = {@JoinColumn(name = "teacherId", referencedColumnName = "id")},
            inverseJoinColumns = {@JoinColumn(name = "lessonId", referencedColumnName = "id")},
            foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT),
            inverseForeignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT))
    @OneToOne
    private Lesson lesson;

}

这样写了之后,程序启动完成,自动创建的 teacher_and_lesson 表中,会多出一个 student_id 出来,

没搞懂是为啥。😭

求大佬指点,谢谢。。。

3600 次点击
所在节点    程序员
30 条回复
Kontinue
2021-02-10 10:52:25 +08:00
我觉得 Spring Data JPA 就是要简化这些东西。同意楼上的,要不就自己手动拼,java8 的 strean 也挺好用的,要不就 querydsl 。通过注解强关联也行,但前提是你对 Hribernate 很熟悉,例如对象管理、dirty check 、级联操作等,否则容易出现问题
beginor
2021-02-10 10:54:31 +08:00
NHibernate 用户路过, 原理都是一样的。

多对多不需要自己管理中间表的,也就是不需要在映射中体现这个表的映射, 只要在多对多映射中说明这个表就行。

可以先试一下 xml 映射, 这个才是 hibernate 的精髓, 不管你怎么写 annotation, 最终都会被翻译成 xml 映射, 所以 xml 映射才是最直接的, 先掌握 xml 映射, 再去学习这些 annotation 映射, 如果直接上手就是 annotation 的话, 碰到稍微高级的映射就不知所措了。

hibernate 还是值得认真学习一下的, 不管是 .net 还是 java,hibernate 都是非常优秀的 orm 框架, 用好了的话在后台管理中还是非常省心和靠谱的。
beginor
2021-02-10 10:57:28 +08:00
反观那些张嘴就说 jpa 和 hibernate 火葬场的, 多数都是不怎么懂 jpa 和 hibernate 的。
NoKey
2021-02-10 11:48:59 +08:00
@Kontinue 通过注解关联起来的好处是后面进行查询,插入等操作的时候,很方便,不用单独去写查询语句,写 sql 或者类 sql 去做这些事当然没问题,现在我就是想试试看,代码中不加入 sql,能否完成平时能做的事情
chanchan
2021-02-10 13:17:52 +08:00
@NoKey join column 确实造不出中间表。中间表的话写好 @manytomany 等注解,hibernate 会自己建
XiLemon
2021-02-10 13:25:18 +08:00
看到 JPA 和头痛,我慌了
bestu
2021-02-10 13:45:31 +08:00
@NoKey 造不出来,因为一对一直接用外键映射即可,一对多和多对一也是,只有在多对多才会维护中间表,不过也是 jpa 自己去维护,使用的话直接调用就可以
NoKey
2021-02-10 15:08:26 +08:00
谢谢各位,问题解决了,报错是 postgresql 的问题,之前用的是 mysql,对 pg 不熟,问题已解决,我上面的代码问题就在于其中一个表名写错了
tedzhou1221
2021-02-10 15:10:29 +08:00
多表关联写的时候爽,后面维护、修改逻辑 那才叫头痛。如果 SQL 别人写得乱一点,这些 SQL 基本就废了。
gjkv86
2021-02-10 15:28:24 +08:00
这看着不是 jpa 的锅,是你把 jpa 用成了面向数据库编程。jpa 首先要对象建模,你这设计看不出有这方面的内容。你把对象关系捋清楚在去熟悉 hibernate 怎么用,前提是你得有这个能力。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/752577

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX