Jpa配置一对多关系

在网上查了很多关于jpa的一对多表关联的操作,踩了很多坑,今天终于解决了

下面上一下我自己的代码,记录一下

老师和学生(一对多关系)

首先搭建环境,添加依赖包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.lyf</groupId>
    <artifactId>one-to-more</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.22</version>
        </dependency>
    </dependencies>
</project>

编写数据库配置文件

spring.datasource.url=jdbc:mysql://localhost:3306/jpa?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=08186912
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.database=mysql

实体类

package com.lyf.pojo;

import lombok.Data;

import javax.persistence.*;

/**
 * @Date:2019-04-12
 * @Description:com.lyf.pojo
 * @version:1.0
 */
@Data
@Entity
@Table(name = "tb_student")
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "s_id")
    private Long sId;
    @Column(name = "s_name")
    private String sName;

    /**
     * 多个学生对应一个老师
     * 注解形式配置多对一
     *  1,配置表关系
     *  2,配置外键
     */
    @ManyToOne(targetEntity = Teacher.class)
    @JoinColumn(name = "s_t_id",referencedColumnName = "t_id")
    private Teacher teacher;
}
package com.lyf.pojo;

import lombok.Data;

import javax.persistence.*;import java.util.HashSet;import java.util.Set;

/** * @Date:2019-04-12 * @Description:教师和学生是一对多 */@Data@Entity@Table(name = "tb_teacher")public class Teacher {    @Id    @GeneratedValue(strategy = GenerationType.IDENTITY)    @Column(name = "t_id")    private Long tId;    @Column(name = "t_name")    private String tName;    //配置老师和学生一对多    /**     * 注解配置多表关系     *  1,声名关系     *  2,配置外键,或者中间表     *  OneToMany配置一对多     *      targetEntity设置对应的实体类的类型     *  JoinColumn 配置外键     *      name:外键的名称,     *      referencedColumnName参照的主表的主键字段名称     */    @OneToMany(targetEntity = Student.class)    @JoinColumn(name = "s_t_id",referencedColumnName = "t_id")    private Set<Student> students = new HashSet<>();}
 

springboot启动类(引导类)

package com.lyf;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @Date:2019-04-12
 * @Description:com.lyf
 * @version:1.0
 */
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class,args);
    }
}

启动引导类,查看数据库会发现表生成成功

dao层代码就不上了,继承JpaRepository就行了

接下来我们进行保存操作

package com.lyf;

import com.lyf.dao.StudentDao;
import com.lyf.dao.TeacherDao;
import com.lyf.pojo.Student;
import com.lyf.pojo.Teacher;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @Date:2019-04-12
 * @Description:com.lyf
 * @version:1.0
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class OneToMoreTest {

    @Autowired
    private TeacherDao teacherDao;
    @Autowired
    private StudentDao studentDao;
    @Test
    public void addTest(){
        Student student = new Student();
        student.setSName("老篮孩i");
        Teacher teacher = new Teacher();
        teacher.setTName("刘老师");
        //关联学生和老师,添加学生信息时,还需添加外键的值
        student.setTeacher(teacher);

        studentDao.save(student);
        teacherDao.save(teacher);
    }
}

结果报错了,发现我是先保存的学生信息,再保存的老师信息,此时数据库中并没有老师的信息,给学生关联老师信息肯定是有问题的

报错信息

org.springframework.dao.InvalidDataAccessApiUsageException:   org.hibernate.TransientPropertyValueException:     object references an unsaved transient instance - save the transient instance before flushing : com.lyf.pojo.Student.teacher -> com.lyf.pojo.Teacher;       nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException:         object references an unsaved transient instance - save the transient instance before flushing :           com.lyf.pojo.Student.teacher -> com.lyf.pojo.Teacher

学生表记录插入了,老师表是空的

改成

package com.lyf;

import com.lyf.dao.StudentDao;
import com.lyf.dao.TeacherDao;
import com.lyf.pojo.Student;
import com.lyf.pojo.Teacher;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @Date:2019-04-12
 * @Description:com.lyf
 * @version:1.0
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class OneToMoreTest {

    @Autowired
    private TeacherDao teacherDao;
    @Autowired
    private StudentDao studentDao;
    @Test
    public void addTest(){
        Student student = new Student();
        student.setSName("老篮孩i");
        Teacher teacher = new Teacher();
        teacher.setTName("刘老师");
        //关联学生和老师,添加学生信息时,还需添加外键的值
        student.setTeacher(teacher);

        //要先保存主表信息
        teacherDao.save(teacher);
        studentDao.save(student);
    }
}

 控制台信息,很显然成功了

Hibernate: alter table tb_student add constraint FKsojy7bicq68v21slcq9mtwtou foreign key (s_t_id) references tb_teacher (t_id)
2019-04-12 23:29:42.036  INFO 10980 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit ‘default‘
2019-04-12 23:29:42.748  INFO 10980 --- [           main] com.lyf.OneToMoreTest                    : Started OneToMoreTest in 7.77 seconds (JVM running for 9.806)
Hibernate: insert into tb_teacher (t_name) values (?)
Hibernate: insert into tb_student (s_name, s_t_id) values (?, ?)

查看数据库也没有问题

同样我们通过Teacher表也能完成关联操作,保存也是没有问题的

@Test
    public void addTest1(){
        Student student = new Student();
        student.setSName("老篮孩i1");
        Teacher teacher = new Teacher();
        teacher.setTName("刘老师1");

        //通过主表来添加关联
        teacher.getStudents().add(student);
        studentDao.save(student);
        teacherDao.save(teacher);
    }

 控制打印信息

Hibernate: insert into tb_student (s_name, s_t_id) values (?, ?)
Hibernate: insert into tb_teacher (t_name) values (?)
Hibernate: update tb_student set s_t_id=? where s_id=?

学生类和老师类都添加类外键的配置,都具备外键的维护,那么我们这里可以通过学生找到老师,也能通过老师找到学生,这是一种双向关系

如果只配置一方,那就是单向的关系,只能通过指定的一方找到另一方

原文地址:https://www.cnblogs.com/a-small-lyf/p/10699326.html

时间: 2024-10-31 09:11:52

Jpa配置一对多关系的相关文章

Configure One-to-Many(配置一对多关系)【Code-First系列】

现在,我们将学习怎么配置一对多的关系. Visit Entity Relationship section to understand how EF manages one-to-one, one-to-many, and many-to-many relationships between the entities. Note: You do not need to configure for one-to-many relationships either using DataAnnotat

【译】第26节---配置一对多关系

原文:http://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx 本节,我们将学习如何在Code First中配置两个实体之间的一对多关系. 举一个Student和Standard(年级)实体的例子,其中,一个Standard可以包括许多Student. 所以Student与Standard实体之间的关系将是一对多的. 使用DataAnnotatio

Configure Many-to-Many(配置多对多关系)【Code-First系列】

现在学习EF Code-First多对多的配置. 这里我们举例:学生和班级实体,一个学生可以选修多个课程,多个学生也可以选修同一个课程. 一.使用数据注解特性,配置多对多的关系 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EF7 { public class Student { public

使用annotation配置hibernate(2):一对多关系配置

数据表结构 单向一对多 Student.java 1 @Entity 2 @Table(name = "student") 3 public class Student { 4 @Id 5 @Column(name = "id") 6 @GenericGenerator(name = "generator",strategy = "native") 7 @GeneratedValue(generator = "gen

MyBatis_4_一对多关系配置

---5-1 一对多关系配置1-------------------------------------------------------------- message package com.imooc.bean; /** * 与消息表对应的实体类 */ public class Message { /** * 主键 */ private String id; /** * 指令名称 */ private String command; /** * 描述 */ private String d

JPA双向一对多多一对一

? 双向一对多关系中,必须存在一个关系维护端,在 JPA 规范中,要求  many 的一方作为关系的维护端(owner side), one 的一方作为被维护端(inverse side). ?可以在 one 方指定 @OneToMany 注释并设置 mappedBy 属性,以指定它是这一关联中的被维护端,many 为维护端. ?在 many 方指定 @ManyToOne 注释,并使用 @JoinColumn 指定外键名称 package com.morris.entity; import ja

Mybatis框架中实现一对多关系映射

学习过Hibernate框架的伙伴们很容易就能简单的配置各种映射关系(Hibernate框架的映射关系在我的blogs中也有详细的讲解),但是在Mybatis框架中我们又如何去实现 一对多的关系映射呢? 其实很简单 首先我们照常先准备前期的环境(具体解释请  参考初识Mybatis进行增.删.改.查 blogs )这里我就直接上代码了 主配置文件:Configuration.xml <?xml version="1.0" encoding="UTF-8" ?&

Hibernate中双向的一对多关系

何为双向,双向的意思就是你我之间可以互相通信(customer(1)和order(n)) 也就是说customer可以访问order,order也可以访问customer 二者构成了双向的关系 在Hibernate中如何实现双向的一对多关系呢?? 步骤: I在1的一端(也就是customer)添加n端(order)的集合列表,并添加get和set方法 package com.jeremy.hibernate.app.example.both; import java.util.HashSet;

[NHibernate]一对多关系(关联查询)

目录 写在前面 文档与系列文章 一对多查询 总结 写在前面 上篇文章介绍了nhibernate的一对多关系如何配置,以及级联删除,级联添加数据的内容.这篇文章我们将学习nhibernate中的一对多关系的关联查询.前面文章中也介绍的nhibernate的查询:HQL,条件查询,原生SQL查询. 文档与系列文章 [Nhibernate]体系结构 [NHibernate]ISessionFactory配置 [NHibernate]持久化类(Persistent Classes) [NHibernat