之前用的 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 出来,
没搞懂是为啥。😭
求大佬指点,谢谢。。。
1
overthemoon 2021-02-09 16:03:40 +08:00
多表打死不用 jpa,mybatis 不香吗
|
2
hly9469 2021-02-09 16:15:19 +08:00 via iPhone
我最终体会就是别用 jpa 的表关联了,关联资源代码里手动组装
|
3
yaojiarui 2021-02-09 16:20:47 +08:00
|
4
gengzi 2021-02-09 16:23:22 +08:00
写原生 sql 即可
|
5
seashell84 2021-02-09 16:23:54 +08:00 via Android
有关联别用 jpa,换 jdbctemplate
|
6
themostlazyman 2021-02-09 16:44:33 +08:00
|
7
AkideLiu 2021-02-09 16:44:37 +08:00
jpa 一时爽,多表火葬场
|
8
AkideLiu 2021-02-09 16:48:09 +08:00
|
9
Cryse 2021-02-09 17:17:19 +08:00 1
|
10
22k 2021-02-09 19:07:06 +08:00
试试用 querydsl-jpa,java 式编程
|
11
NoKey OP @themostlazyman 谢谢,修改了,然后跑不起来了,报错
is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.tool.schema.spi.SchemaManagementException: Export identifier [student_and_teacher] encountered more than once |
13
crclz 2021-02-09 23:00:07 +08:00
1. 业务类的,手动查
2. 查询类的,用 EntityManager 写 SQL ( JPQL )查询,反正 IDEA 的提示是挺好用的。 |
14
NoKey OP 我重新调整了一下代码
student teacher student-teacher 这三个一起,ok 了 teacher lesson teacher-lesson 这三个一起,ok 了 然而,这几个混到一起的时候,就运行不起来了,报错 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.tool.schema.spi.SchemaManagementException: Export identifier [student_and_teacher] encountered more than once |
15
bestu 2021-02-09 23:34:48 +08:00 via Android
one to one 不应该 join column 吗
|
16
evi1j 2021-02-10 08:27:22 +08:00 via Android
EntityManager 不是美滋滋
|
17
Thetruechar 2021-02-10 09:15:18 +08:00 via Android
别用 orm 直接写 sql
|
18
chanchan 2021-02-10 09:30:17 +08:00 via Android
中间表不需要自己管理,我平时用 join column 感觉更方便。
|
21
Kontinue 2021-02-10 10:52:25 +08:00
我觉得 Spring Data JPA 就是要简化这些东西。同意楼上的,要不就自己手动拼,java8 的 strean 也挺好用的,要不就 querydsl 。通过注解强关联也行,但前提是你对 Hribernate 很熟悉,例如对象管理、dirty check 、级联操作等,否则容易出现问题
|
22
beginor 2021-02-10 10:54:31 +08:00 via Android
NHibernate 用户路过, 原理都是一样的。
多对多不需要自己管理中间表的,也就是不需要在映射中体现这个表的映射, 只要在多对多映射中说明这个表就行。 可以先试一下 xml 映射, 这个才是 hibernate 的精髓, 不管你怎么写 annotation, 最终都会被翻译成 xml 映射, 所以 xml 映射才是最直接的, 先掌握 xml 映射, 再去学习这些 annotation 映射, 如果直接上手就是 annotation 的话, 碰到稍微高级的映射就不知所措了。 hibernate 还是值得认真学习一下的, 不管是 .net 还是 java,hibernate 都是非常优秀的 orm 框架, 用好了的话在后台管理中还是非常省心和靠谱的。 |
23
beginor 2021-02-10 10:57:28 +08:00 via Android
反观那些张嘴就说 jpa 和 hibernate 火葬场的, 多数都是不怎么懂 jpa 和 hibernate 的。
|
24
NoKey OP @Kontinue 通过注解关联起来的好处是后面进行查询,插入等操作的时候,很方便,不用单独去写查询语句,写 sql 或者类 sql 去做这些事当然没问题,现在我就是想试试看,代码中不加入 sql,能否完成平时能做的事情
|
25
chanchan 2021-02-10 13:17:52 +08:00 via Android
@NoKey join column 确实造不出中间表。中间表的话写好 @manytomany 等注解,hibernate 会自己建
|
26
XiLemon 2021-02-10 13:25:18 +08:00 via iPhone
看到 JPA 和头痛,我慌了
|
27
bestu 2021-02-10 13:45:31 +08:00 via Android
@NoKey 造不出来,因为一对一直接用外键映射即可,一对多和多对一也是,只有在多对多才会维护中间表,不过也是 jpa 自己去维护,使用的话直接调用就可以
|
28
NoKey OP 谢谢各位,问题解决了,报错是 postgresql 的问题,之前用的是 mysql,对 pg 不熟,问题已解决,我上面的代码问题就在于其中一个表名写错了
|
29
tedzhou1221 2021-02-10 15:10:29 +08:00
多表关联写的时候爽,后面维护、修改逻辑 那才叫头痛。如果 SQL 别人写得乱一点,这些 SQL 基本就废了。
|
30
gjkv86 2021-02-10 15:28:24 +08:00 via iPhone
这看着不是 jpa 的锅,是你把 jpa 用成了面向数据库编程。jpa 首先要对象建模,你这设计看不出有这方面的内容。你把对象关系捋清楚在去熟悉 hibernate 怎么用,前提是你得有这个能力。
|