GVKun编程网logo

MyBatis查询:多对一映射关系(mybatis多对多映射)

10

关于MyBatis查询:多对一映射关系和mybatis多对多映射的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于Hibernate中的一对一映射关系、Hibernate单向多对一映射关系0

关于MyBatis查询:多对一映射关系mybatis多对多映射的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于Hibernate中的一对一映射关系、Hibernate单向多对一映射关系01和级联保存和Junit4使用、Hibernate双向一对一映射关系配置代码实例、Hibernate双向多对一映射关系02双向级联,维护主外键关系等相关知识的信息别忘了在本站进行查找喔。

本文目录一览:

MyBatis查询:多对一映射关系(mybatis多对多映射)

MyBatis查询:多对一映射关系(mybatis多对多映射)

通过级联属性复制解决多对一的映射关系

通过association解决多对一的映射关系

 

 

 

通过级联属性复制解决多对一的映射关系

 

 

Mapper层

@Mapper
public interface ParameterMapper {
    Emp GetEmpAndDept(@Param("id") Integer eid);
}

 

映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mybatis_review.mapper.ParameterMapper">
    <resultMap id="GetEmpAndDeptMap" type="com.example.mybatis_review.bean.Emp">
        <id property="eid" column="eid"></id>
        <result property="age" column="age"></result>
        <result property="email" column="email"></result>
        <result property="empName" column="emp_name"></result>
        <result property="did" column="did"></result>
        <result property="dept.did" column="did"></result>
        <result property="dept.deptName" column="dept_name"></result>
    </resultMap>
<!--    Emp GetEmpAndDept(@Param("id") Integer eid);-->
    <select id="GetEmpAndDept" resultMap="GetEmpAndDeptMap">
        select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid=#{id}
    </select>
</mapper>

 

 

 

 

通过association解决多对一的映射关系

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mybatis_review.mapper.ParameterMapper">
    <resultMap id="GetEmpAndDeptMap" type="com.example.mybatis_review.bean.Emp">
        <id property="eid" column="eid"></id>
        <result property="age" column="age"></result>
        <result property="email" column="email"></result>
        <result property="empName" column="emp_name"></result>
        <result property="did" column="did"></result>
        <association property="dept" javaType="com.example.mybatis_review.bean.Dept">
            <id property="did" column="did"></id>
            <result property="deptName" column="dept_name"></result>
        </association>
    </resultMap>
<!--    Emp GetEmpAndDept(@Param("id") Integer eid);-->
    <select id="GetEmpAndDept" resultMap="GetEmpAndDeptMap">
        select * from t_emp left join t_dept on t_emp.did = t_dept.did where t_emp.eid=#{id}
    </select>
</mapper>

 

Hibernate中的一对一映射关系

Hibernate中的一对一映射关系

Hibernate中的一对一映射关系有两种实现方法(单向一对一,和双向一对一)(一对一关系:例如一个department只能有一个manager)

单向和双向有什么区别呢??
例如若是单向一对一,比如在department中插入一个外键关联manager表(manager_id),那此时插入数据时,就必须先插入manager表的数据再插入department表的数据,而且使用Hibernate检索数据时,查询department的数据,如果没有使用懒加载,则manager的对应的数据也会被查询处出来,
但是如果是双向一对一,可以任意插入一方的数据,查询数据时,无论查询哪一方,被关联方也会被检索处理

  I单向一对一

  配置步骤:

  ①:分析1端和n端(如果是一对一关系的时候,可以选择任意一方为N端,)

  ②:在1端插入n端的集合属性(因为是一对一,所以不可以使集合对象属性,只能使用对象属性)

  ③:在n端插入一端的对象属性

  ④:注明关系在那一段维护

  步骤:1在一对一关联的持久化类中互相添加对方对象属性,
       例如在department中添加private manager manager属性:

       department代码如下:

package com.atguigu.hibernate.one2one.foreign;

public class Department {

    private Integer deptId;
    private String deptName;
    
    private Manager mgr;

    public Integer getDeptId() {
        return deptId;
    }

    public void setDeptId(Integer deptId) {
        this.deptId = deptId;
    }

    public String getDeptName() {
        return deptName;
    }

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

    public Manager getMgr() {
        return mgr;
    }

    public void setMgr(Manager mgr) {
        this.mgr = mgr;
    }
    
    
    
}

    manager的代码:

    

package com.atguigu.hibernate.one2one.foreign;

public class Manager {

    private Integer mgrId;
    private String mgrName;
    
    private Department dept;

    public Integer getMgrId() {
        return mgrId;
    }

    public void setMgrId(Integer mgrId) {
        this.mgrId = mgrId;
    }

    public String getMgrName() {
        return mgrName;
    }

    public void setMgrName(String mgrName) {
        this.mgrName = mgrName;
    }

    public Department getDept() {
        return dept;
    }

    public void setDept(Department dept) {
        this.dept = dept;
    }
    
    
    
}

    2对于基于外键的1-1关联,其外键可以存放在任意一边,在需要存放外键一端,增加many-to-one元素。为many-to-one元素且增加unique=“true” 属性来表示为1-1关联

    

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>

    <class name="com.atguigu.hibernate.one2one.foreign.Department" table="DEPARTMENTS">

        <id name="deptId" type="java.lang.Integer">
            <column name="DEPT_ID" />
            <generator class="native" />
        </id>
        
        <property name="deptName" type="java.lang.String">
            <column name="DEPT_NAME" />
        </property>
        
        <!-- 使用 many-to-one 的方式来映射 1-1 关联关系,其实many-to-one 就是可以用来生成外键 -->
     <many-to-one name="mgr"column="MGR_ID" unique="true">
    </many-to-one>                     
    </class>
</hibernate-mapping>

 

  另一端需要使用one-to-one元素,该元素使用 property-ref 属性指定使用被关联实体主键以外的字段作为关联字段(就是要指定外键是哪一个,记得是使用Java的属性名,不是使用Sql的列名)

  

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

    <class name="com.atguigu.hibernate.one2one.foreign.Manager" table="MANAGERS">
        
        <id name="mgrId" type="java.lang.Integer">
            <column name="MGR_ID" />
            <generator class="native" />
        </id>
        
        <property name="mgrName" type="java.lang.String">
            <column name="MGR_NAME" />
        </property>
        
        <!-- 映射 1-1 的关联关系: 在对应的数据表中已经有外键了, 当前持久化类使用 one-to-one 进行映射 -->
        <!-- 
            没有外键的一端需要使用one-to-one元素,该元素使用 property-ref 属性指定使用被关联实体主键以外的字段作为关联字段
         -->
        <one-to-one name="dept" class="com.atguigu.hibernate.one2one.foreign.Department" 
      property-ref="mgr"></one-to-one> </class> </hibernate-mapping>

对于一对一关联映射,记得千万不要两张表都设置外键,这样会引起逻辑错误的

 

II双向一对一映射关系
  步骤:1在一对一关联的持久化类中互相添加对方对象属性,
       例如在department中添加private manager manager属性:这个代码跟I那里没区别,都一样

      2在需要生成外键的那个表对应的持久化类的.hbm.xml文件中指定主键的映射策略为foreign策略,
     表明根据”对方”的主键来生成自己的主键,自己并不能独立生成主键. <param> 子元素指定使用
     当前持久化类的哪个属性作为 “对方” 采用foreign主键生成器策略的一端增加 one-to-one 元素
       映射关联属性,其one-to-one属性还应增加 constrained=“true” 属性

     代码如下:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.atguigu.hibernate.one2one.primary">
    <class name="Department" table="DEPARTMENTS">

        <id name="deptId" type="java.lang.Integer">
            <column name="DEPT_ID" />
            <!-- 使用外键的方式来生成当前的主键 -->
            <generator class="foreign">
                <!-- property 属性指定使用当前持久化类的哪一个属性的主键作为外键 -->
                <param name="property">mgr</param>
            </generator>
        </id>
        
        <property name="deptName" type="java.lang.String">
            <column name="DEPT_NAME" />
        </property>
        
        <!--  
        采用 foreign 主键生成器策略的一端增加 one-to-one 元素映射关联属性,
        其 one-to-one 节点还应增加 constrained=true 属性, 以使当前的主键上添加外键约束
        -->
        <one-to-one name="mgr" class="Manager" constrained="true"></one-to-one>
                            
    </class>
</hibernate-mapping>

另一端增加one-to-one元素映射关联属性。

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

    <class name="com.atguigu.hibernate.one2one.primary.Manager" table="MANAGERS">
        
        <id name="mgrId" type="java.lang.Integer">
            <column name="MGR_ID" />
            <generator class="native" />
        </id>
        
        <property name="mgrName" type="java.lang.String">
            <column name="MGR_NAME" />
        </property>
        
        <one-to-one name="dept" class="com.atguigu.hibernate.one2one.primary.Department">
     </
one-to-one> </class> </hibernate-mapping>

以上就是一对一映射关系的配置,不过有没有想到,当从不同的表来访问关联表的数据,访问过程是怎样的???()

Hibernate单向多对一映射关系01和级联保存和Junit4使用

Hibernate单向多对一映射关系01和级联保存和Junit4使用

一、了解什么是一对多?

     一对多这种关系用的很多,但是很多人对此模糊不清,一对多不也就是多对一吗,多对多中特殊的一个不也就是一对多吗,为什么还分的那么清楚?并且还是什么单向和双向的那么麻烦,其实原因很简单,就是针对不同的情况和业务需求而产生的这种说法

     例如:学生和班级

        单向一对多:一个班级对应多个学生。 也就是说,在某种业务情况下,我只需要知道从一个班级中知道有哪些学生,但是我不需要知道一个学生在哪个班级,这时候我就没必要写通过学生能查找到对应班级这个业务

站在“”这一边,可以通过班级看这个班级的学生功能,没有通过学生知道班级功能)

        单向多对一:多个学生对应一个班级,可以通过每个学生查找到所在的班级名称,而不能从班级中查找到有哪些学生在里面,这就是从多到一的单面考虑,也就是说,当我们的业务需求只需要通过学生能找到对应班级,而不需要通过班级知道有哪些学生的时候,就可以写这样的单向多对一的关系映射

(站在“”这一边,有通过学生知道班级功能,没有通过班级看这个班级的学生功能)

        双向一对多/双向多对一:这两个是一个意思,既然度双向了,说明不管从哪一方去找另一方,度可以找得到,也就无所谓一对多,还是多对一了。从这个学生和班级来讲,通过学生能知道他所在的班级,通过班级,能知道该班级下所有的学生。

      通过这个例子就知道了单向和双向是干嘛用的,就是根据不同的业务所规定的,如果你需要双向就写双向的映射关系,如果只需要从一方到另一方,那么就写自己所需要的,单向一对多或者单向多对一。

     

    所以我们接下要讲解的就是这三种,单向一对多、单向多对一、双向一对多。

二、单向多对一

      多个用户属于同一个组,多个学生属于同一个班级,多个学生属于同一个宿舍,等等,很多关系是这种多对一。

      多个学生属于同一个班级。单向多对一    

                  UserClasses类的关系图。

               

知道需要的功能是多对一之后,站在“多的角度”,在设计完学生类基本属性的情况下,增加一个“班级类”来保存班级信息,就是说该学生数据有这个班级表信息

例子

1、首先创建班级和学生实体类

Classes.java

package com.java.model;

public class Classes {
	private String name;
	private long id;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	
}

配置Classes.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
       <!--班级表class name对应类名,table对应数据库中的表名  -->
	<class name="com.java.model.Classes" table="t_classes">
	
	<!--主键id name对应实体类的属性,column对应数据库表中的字段 ,generator主键 -->
	<id name="id" column="class_id">
		<generator></generator>
	</id>
	
		<!-- 该对象的基本属性 -->
	<property name="name" column="class_name">
	</property>
	</class>


</hibernate-mapping>

 

因为是多对一,站在“多”的角度,也就站在学生角度,classes 班级 不需要有那种关系,只需要配置自己的属性就行了

 

Student.java

package com.java.model;

public class Student {
	private String name;
	private long id;
	
	//定义一个班级对象
	private Classes c;

	public Classes getC() {
		return c;
	}
	public void setC(Classes c) {
		this.c = c;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	

	
	@Override
	public String toString() {
		return "Student [name=" + name + ", id=" + id + ", c=" + c + "]";
	}
	
	

}

 Student需要有相应的能力,所以需要配置外键关系。many to one

Student.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
       <!--学生表class name对应类名,table对应数据库中的表名  -->
	<class name="com.java.model.Student" table="t_student">
	
	<!--主键id name对应实体类的属性,column对应数据库表中的字段 ,generator主键 -->
	<id name="id" column="student_id">
		<generator></generator>
	</id>
	
	<!-- 该对象的基本属性 -->
	<property name="name" column="student_name">
	</property>
	
	
	 <!-- 重点在这里 
	 		学生表外键和班级表主键相关联,
            name:学生实体类中定义的那个对象的引用名称这东西:private Class c;。
            column:学生表中的外键名称。注意,是被外键约束的字段的名称,写这些配置文件,要时刻记得那两张数据库表的关系。
			学生表外键名可以取和班级表主键名不一样的名字
			本例学生表外键名:classId  
			本例班级表主键名:class_id  
         -->
	<many-to-one name="c" column="classId"></many-to-one>
	</class>


</hibernate-mapping>

单向多对一的关系映射就是这样,原理就是在数据库中多方设置外键指向一方。 然后通过映射文件来利用这个外键帮我们达到我们的目的,这里就是通过外键,找到对应的班级放入我们自己类中的classes属性中。

many-to-one的属性

        name:影射类属性的名称

        class:非必须的,不写,hibernate会自己根据name的值去查找

        column:关联的字段,也是非必须的,hibernate也会帮我们在查找,但是不写的话,User中的外键名称必须和Classes中的主键名称相同。也就是关联的字段名称要相同,这样才找得到

        net-null:默认是false,就是不能为空

        

 

然后执行/StudentTest.java

package com.java.service;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.java.util.HibernateUtil;
public class StudentTest {

	public static void main(String[] args) {
		SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
		  Session session=sessionFactory.openSession(); // 生成一个session
		    session.beginTransaction(); // 开启事务
		    
		  
		    
		    session.getTransaction().commit(); // 提交事务
		    session.close(); // 关闭session
	}
}

查看数据库,发现自动生成了表,还有主外键的关联关系,神奇

三、“多对一”级联保存

一般我们写入数据进数据步骤是:

1.操作班级表,给班级表创建一条班级数据

2.操作学生表,给学生表创建一条学生数据,然后放入班级信息

package com.java.service;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.java.model.Classes;
import com.java.model.Student;
import com.java.util.HibernateUtil;
public class StudentTest {

	public static void main(String[] args) {
		SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
		  Session session=sessionFactory.openSession(); // 生成一个session
		    session.beginTransaction(); // 开启事务

		    //写好班级信息
		    Classes banji=new Classes();
		    banji.setName("15软件工程");
                    //持久化,操作班级表,把班级信息放到数据库
		    session.save(banji);
		     
                    //写好学生表的信息
		    Student s1=new Student();
		    s1.setName("张三");
		    s1.setC(banji);
                    //持久化,操作学生表,把学生信息放到数据库
		     session.save(s1);


		    Student s2=new Student();
		    s2.setName("李四");
                    s2.setC(banji);
		    session.save(s2);
		    
		    session.getTransaction().commit(); // 提交事务
		    session.close(); // 关闭session
	}
}

因为我们设置了单向多对一,也就是说,我们可以只操作学生表,同时操作班级表

当我们在学生表保存学生信息和班级信息,班级表自动保存,级联保存先配置“多”的这边

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
       <!--学生表class name对应类名,table对应数据库中的表名  -->
	<class name="com.java.model.Student" table="t_student">
	
	<!--主键id name对应实体类的属性,column对应数据库表中的字段 ,generator主键 -->
	<id name="id" column="student_id">
		<generator></generator>
	</id>
	
	<!-- 该对象的基本属性 -->
	<property name="name" column="student_name">
	</property>
	
	
	 <!-- 重点在这里 
	 		学生表外键和班级表主键相关联,
            name:学生实体类中定义的那个对象的引用名称:private Class c;。
            column:学生表中的外键名称。注意,是被外键约束的字段的名称,写这些配置文件,要时刻记得那两张数据库表的关系。
			学生表外键名可以取和班级表主键名不一样的名字
			本例学生表外键名:classId  
			本例班级表主键名:class_id  
         -->
	<many-to-one name="c" column="classId"cascade="save-update"></many-to-one>
	</class>


</hibernate-mapping>

现在就可以级联保存,保存学生表的数据,班级表数据就自动生成

package com.java.service;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.java.model.Classes;
import com.java.model.Student;
import com.java.util.HibernateUtil;
public class StudentTest {

	public static void main(String[] args) {
		SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
		  Session session=sessionFactory.openSession(); // 生成一个session
		    session.beginTransaction(); // 开启事务

		    //写好班级信息对象
		    Classes banji=new Classes();
		    banji.setName("15软件工程");
                    		     
                    //写好学生的信息对象		    
                    Student s1=new Student();
		    s1.setName("张三");
                    //把班级信息对象加到学生的信息对象
		    s1.setC(banji);

                    //持久化,只操作学生表,把学生信息对象放到学生表
		     session.save(s1);


		    Student s2=new Student();
		    s2.setName("李四");
                    s2.setC(banji);
		    session.save(s2);
		    
		    session.getTransaction().commit(); // 提交事务
		    session.close(); // 关闭session
	}
}

这样添加学生信息时把班级信息写上点击确定就行,自动把班级信息保存。

不用先保存班级信息,才能保存学生信息。直接保存学生信息即可

数据库:

学生表

班级表

 

四、Junit4使用

Junit方法如下

使用这些方法看先后执行顺序

StudentTest2 

package com.java.service;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class StudentTest2 {

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		System.out.println("类初始化前调用");
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
		System.out.println("类初始化前调用");
	}

	@Before
	public void setUp() throws Exception {
		System.out.println("测试方法前调用");
	}

	@After
	public void tearDown() throws Exception {
		System.out.println("测试方法后调用");
	}

	@Test
	public void test() {
		System.out.println("测试方法");
	}

}

执行顺序结果

常用的就是测试方法前后调用

package com.java.service;

import static org.junit.Assert.*;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.java.model.Classes;
import com.java.model.Student;
import com.java.util.HibernateUtil;

public class StudentTest2 {

	private SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
	private Session session;
	
	@Before
	public void setUp() throws Exception {
	    session=sessionFactory.openSession(); // 生成一个session
	    session.beginTransaction(); // 开启事务
	}

	@After
	public void tearDown() throws Exception {
		 session.getTransaction().commit(); // 提交事务
		 session.close(); // 关闭session
	}
	
	@Test
	public void testSaveClassAndStudent() {
		System.out.println("正常思路保存数据");

	    //写好班级信息
	    Classes banji=new Classes();
	    banji.setName("15软件工程");
                //持久化,操作班级表,把班级信息放到数据库
	    session.save(banji);
	     
                //写好学生表的信息
	    Student s1=new Student();
	    s1.setName("张三");
	    s1.setC(banji);
                //持久化,操作学生表,把学生信息放到数据库
	     session.save(s1);


	    Student s2=new Student();
	    s2.setName("李四");
                s2.setC(banji);
	    session.save(s2);

	}
	@Test
	public void testSaveClassAndStudentWithCascade() {
		System.out.println("级联保存");

		 //写好班级信息
	    Classes banji=new Classes();
	    banji.setName("15软件工程");
                		     
                //写好学生的信息		    
                Student s1=new Student();
	    s1.setName("张三");
	    s1.setC(banji);

                //持久化,只操作学生表,把学生信息放到学生表
	     session.save(s1);


	    Student s2=new Student();
	    s2.setName("李四");
                s2.setC(banji);
	    session.save(s2);


	}

}

想测试哪个方法就进行如下操作:

 

五、单向多对一 

          说了单向多对一,现在来说说单向一对多,根据前面我们讲的,其实就是换了一个角度去想这个问题,学生和班级,现在站在班级这方去看,肯定是需要通过班级能知晓所有在这个班学习的同学的信息。  

         注意方向:站在“一”的角度看待问题,班级是“一”,就是说每一个班级里都有几十个学生信息,通过班级这个表我可以找到某个学生信息

站在“一”的角度,在设计完班级类基本属性的情况下,增加一个“学生类的集合”(每个学生类代表一个学生)

在model的加学生集合属性

private Set<Student> students=new HashSet<Student>();

 

       

       数据库中还是没变,不管是单向一对多还是单向多对一,永远都市通过外键来维护关系的,单向多对一:通过映射文件知道,User的外键能够查找到对应的班级。单向一对多:又是怎么来实现通过User的外键找到属于本班的所有学生的呢?

看代码

Classes.java

package com.java.model;

import java.util.HashSet;
import java.util.Set;

public class Classes {
	private String name;
	private long id;
        <!--重点-->
	private Set<Student> students=new HashSet<Student>();
	
	
	public Set<Student> getStudents() {
		return students;
	}
	public void setStudents(Set<Student> students) {
		this.students = students;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	
}

  Classes.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
       <!--班级表class name对应类名,table对应数据库中的表名  -->
	<class name="com.java.model.Classes" table="t_classes">
	
	<!--主键id name对应实体类的属性,column对应数据库表中的字段 ,generator主键 -->
	<id name="id" column="class_id">
		<generator></generator>
	</id>
	
		<!-- 该对象的基本属性 -->
	<property name="name" column="class_name">
	</property>
	
	
	
        <!--关键在这里,
            name:set集合属性的名称(model里的classes类的学生集合名称)
            key/column:这个是外键名,这个外键字段名不一定要和本类的主键字段名相同,这点要搞清楚,记住数据库表的关系,谁指向谁就不会混淆
                        这个外键值放在学生表里(不管是单向一对多还是单向多对一,都需要在多方加上外键)
            one to many/class:一对多,所映射的类名(全限定类名,直接写类名也可以,hibernate会帮我们自动写好)
        -->
		        <set name="students">
		            <key column="cid"></key>
		            <one-to-many/>
		        </set>
		</class>
</hibernate-mapping>

         通过映射文件可以知道,通过本类(班级)中的主键值去寻找映射类(学生)中的外键值,有匹配的就将其对象放置到set集合中来。所以说,不管是单向一对多还是单向多对一,都需要在多方加上外键,也就是说,他们的原理度是一样的,只是站的角度不一样,单向一对多站的角度在于一方,一方如何通过外键来达到自己的目的,就看自己的映射文件如何编写,单向多对一站的角度在多方,多方如何通过外键来达到自己的目的,也要看自己的映射文件的编写。  

    由于是一对多,站在“一”的角度,学生端正常设置就行

Student.java

package com.java.model;

public class Student {
	private String name;
	private long id;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	
}

Student.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
       <!--学生表class name对应类名,table对应数据库中的表名  -->
	<class name="com.java.model.Student" table="t_student">
	
	<!--主键id name对应实体类的属性,column对应数据库表中的字段 ,generator主键 -->
	<id name="id" column="student_id">
		<generator></generator>
	</id>
	
	<!-- 该对象的基本属性 -->
	<property name="name" column="student_name">
	</property>
	

	</class>


</hibernate-mapping>

 

测试方法(把数据库表删了,因为前面生成了“多对一”的表,现在测试“一对多”)

StudentTest.java

@Test
public static void main(String[] args) {
		SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
		  Session session=sessionFactory.openSession(); // 生成一个session
		    session.beginTransaction(); // 开启事务
		    
		   
		    
		    session.getTransaction().commit(); // 提交事务
		    session.close(); // 关闭session
	}

发现数据库生成成功

、“一对多”级联保存

保存班级表的时候带上学生信息,只操作班级表,学生表也会保存。

首先给Classes.hbm.xml配置cascade="save-update"

然后测试方法

       @Test
	public void testSaveClassAndStudent() {
		//写好班级信息对象
		Classes c=new Classes();
	    c.setName("08计本");
	    //写好学生信息对象
	    Student s1=new Student();
	    s1.setName("张三");
	    
	    Student s2=new Student();
	    s2.setName("李四");
	    
	    //把学生对象加到班级对象
	    c.getStudents().add(s1);
	    c.getStudents().add(s2);
	    
	    //将班级对象保存到班级表中,学生表自动更新
	    session.save(c);
	}

结果

 

 

Hibernate双向一对一映射关系配置代码实例

Hibernate双向一对一映射关系配置代码实例

这篇文章主要介绍了Hibernate双向一对一映射关系配置代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

1、外键映射

1.1、实体类package com.yl.bean; import java.io.Serializable; /** * 公民实体类 */ public class Person implements Serializable { private Integer id; private String name; private PersonCard card; public Person() { } public Person(Integer id, String name, PersonCard card) { this.id = id; this.name = name; this.card = card; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public PersonCard getCard() { return card; } public void setCard(PersonCard card) { this.card = card; } @Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + ''' + ", card=" + card + '}'; } }package com.yl.bean; import java.io.Serializable; /** * 身份证实体类 */ public class PersonCard implements Serializable { private Integer id; private String cardNo; private Person person; public PersonCard() { } public PersonCard(Integer id, String cardNo, Person person) { this.id = id; this.cardNo = cardNo; this.person = person; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getCardNo() { return cardNo; } public void setCardNo(String cardNo) { this.cardNo = cardNo; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } @Override public String toString() { return "PersonCard{" + "id=" + id + ", cardNo='" + cardNo + ''' + ", person=" + person + '}'; } }1.2、全局配置文件(hibernate.cfg.xml)com.MysqL.cj.jdbc.Driverjdbc:MysqL://localhost:3306/hibernate?characterEncoding=utf8&serverTimezone=GMT%2B8root123456trueupdate1.3、公民映射配置文件(Person.hbm.xml)1.4、身份证映射配置文件(PersonCard.hbm.xml)1.5、测试类@Test public void test01(){ Person person=new Person(); person.setName("yl001"); PersonCard personCard=new PersonCard(); personCard.setCardNo("001"); person.setCard(personCard); personCard.setPerson(person); Session session= HibernateUtils.getSession(); Transaction transaction=session.beginTransaction(); session.save(person); session.save(personCard); transaction.commit(); session.close(); }2、主键映射表的字段既是主键,又是外键(eg:身份证号码既是主键又是外键)2.1、映射配置文件实现主要修改PersonCard.hbm.xml文件以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小编。

Hibernate双向多对一映射关系02双向级联,维护主外键关系

Hibernate双向多对一映射关系02双向级联,维护主外键关系

一、双向一对多

双向一对多==双向多对一,就是通过双方度能够找到对方的信息。

 数据库关系:跟单向一对多和单向多对一是一样的。

实例

Student.java

package com.java.model;

public class Student {
	private String name;
	private long id;
	
    //定义一个班级对象
	private Classes c;

	public Classes getC() {
		return c;
	}
	public void setC(Classes c) {
		this.c = c;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", id=" + id + ", c=" + c + "]";
	}
	

}

Student.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
       <!--学生表class name对应类名,table对应数据库中的表名  -->
	<class name="com.java.model.Student" table="t_student">
	
	<!--主键id name对应实体类的属性,column对应数据库表中的字段 ,generator主键 -->
	<id name="id" column="student_id">
		<generator></generator>
	</id>
	
	<!-- 该对象的基本属性 -->
	<property name="name" column="student_name">
	</property>
	
	
	 <!-- 重点在这里 
	 		学生表外键和班级表主键相关联,
            name:学生实体类中定义的那个对象的引用名称:private Class c;。
            column:学生表中的外键名称。注意,是被外键约束的字段的名称,写这些配置文件,要时刻记得那两张数据库表的关系。
			学生表外键名可以取和班级表主键名不一样的名字
			本例学生表外键名:classId  
			本例班级表主键名:class_id  
         -->
         
	 <many-to-one name="c" column="classId"cascade="save-update"></many-to-one>
	 
	</class>


</hibernate-mapping>

Classes.java

package com.java.model;

import java.util.HashSet;
import java.util.Set;

public class Classes {
	private String name;
	private long id;
	private Set<Student> students=new HashSet<Student>();
	
	
	public Set<Student> getStudents() {
		return students;
	}
	public void setStudents(Set<Student> students) {
		this.students = students;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	@Override
	public String toString() {
		return "Classes [name=" + name + ", id=" + id + "]";
	}
	
}

Classes.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
       <!--班级表class name对应类名,table对应数据库中的表名  -->
	<class name="com.java.model.Classes" table="t_classes">
	
	<!--主键id name对应实体类的属性,column对应数据库表中的字段 ,generator主键 -->
	<id name="id" column="class_id">
		<generator></generator>
	</id>
	
		<!-- 该对象的基本属性 -->
	<property name="name" column="class_name">
	</property>
	
	
	
        <!--关键在这里,
            name:set集合属性的名称(model里的classes类的学生集合名称)
            key/column:这个是外键名,这个外键字段名不一定要和本类的主键字段名相同,这点要搞清楚,记住数据库表的关系,谁指向谁就不会混淆
                        这个外键值放在学生表里(不管是单向一对多还是单向多对一,都需要在多方加上外键)
            one to many/class:一对多,所映射的类名(全限定类名,直接写类名也可以,hibernate会帮我们自动写好)
        -->
		        <set name="students" cascade="save-update">
		            <key column="classId"></key>
		            <one-to-many/>
		        </set>
		</class>
</hibernate-mapping>

导入映射文件hibernate.cfg.xml

<?xml version=''1.0'' encoding=''utf-8''?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <!--数据库连接设置 -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property>
        <property name="connection.username">root</property>
        <property name="connection.password">123456</property>

       
        <!-- 方言 -->
        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
	
        <!-- 控制台显示SQL -->
        <property name="show_sql">true</property>

        <!-- 自动更新表结构 -->
        <property name="hbm2ddl.auto">update</property>
        
      <!--导入映射文件-->
	  	<mapping resource="com/java/model/Student.hbm.xml"/>
	  	<mapping resource="com/java/model/Classes.hbm.xml"/>

    </session-factory>

</hibernate-configuration>

测试类

package com.java.service;

import static org.junit.Assert.*;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.java.model.Classes;
import com.java.model.Student;
import com.java.util.HibernateUtil;

public class StudentTest2 {

	private SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
	private Session session;
	
	@Before
	public void setUp() throws Exception {
		session=sessionFactory.openSession(); // 生成一个session
	    session.beginTransaction(); // 开启事务
	}

	@After
	public void tearDown() throws Exception {
		 session.getTransaction().commit(); // 提交事务
		 session.close(); // 关闭session
	}
	
	
	@Test
	public void testSaveClassAndStudentWithCascade() {
		System.out.println("通过操作学生表进行级联保存");

		 //写好班级对象
	    Classes banji=new Classes();
	    banji.setName("15数媒");
                		     
          //写好学生的对象		    
         Student s1=new Student();
	    s1.setName("王五");
	    //将班级信息保存到学生对象中
	    s1.setC(banji);

	    Student s2=new Student();
	    s2.setName("赵六");
        s2.setC(banji);
	      //持久化,只操作学生表,把学生信息放到学生表,班级表自动更新
		session.save(s1);
	    session.save(s2);


	}
	
	@Test
	public void testSaveClassAndStudentWithCascade2() {
		System.out.println("通过操作班级表进行级联保存");
		//写好班级信息对象
		Classes c=new Classes();
	    c.setName("15软件");
	    //写好学生信息对象
	    Student s1=new Student();
	    s1.setName("张三");
	    
	    Student s2=new Student();
	    s2.setName("李四");
	    
	    //把学生对象加到班级对象
	    c.getStudents().add(s1);
	    c.getStudents().add(s2);
	    
	    //将班级对象保存到班级表中,学生表自动更新
	    session.save(c);
	}
	

}

结果

二、根据数据表调出数据

@Test
	public void getStudentsByClass(){
		System.out.println("从班级表中获取学生信息");
		Classes c=(Classes)session.get(Classes.class, Long.valueOf(2));
		Set<Student> students=c.getStudents();
		Iterator it=students.iterator();
		while(it.hasNext()){
			Student s=(Student)it.next();
			System.out.println(s);
		}
	}
	@Test
	public void getClassByStudents(){
		System.out.println("从学生表中获取该学所在班级的信息");
		Student s=(Student)session.get(Student.class, Long.valueOf(5));
		Classes classes=  s.getC();
			System.out.println(classes);
		
	}

三、关联维护

在多对多关联中,如果设置了inverse="true"就表示本方不进行关联的维护,由另一方进行关联的维护。

在一对多的关系中,一般有“多”方进行关联维护,所以Classes.hbm.xml设置inverse="true"(班级表不进行关联维护)

首先我们先写一个添加数据方法,但不添加他们的关系

        @Test
	public void testAdd(){
		Classes c=new Classes();
	    c.setName("16信息与技术");
	    
	    Student s1=new Student();
	    s1.setName("王五");
	    
	    session.save(c);
	    session.save(s1);
	}

外键为空,说明班级和学生没有联系

添加关联

@Test
	public void testInverse(){
		Classes c=(Classes)session.get(Classes.class, Long.valueOf(4));
		Student s=(Student)session.get(Student.class, Long.valueOf(9));
		
                 //学生添加班级
		s.setC(c);
                 //班级添加学生
		c.getStudents().add(s);
	}

添加完成但是我们发现写了两条sql语句

我们只需要在学生端维护主外键关系即可,inverse让某一端来维护主外键关系

Classes.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
       <!--班级表class name对应类名,table对应数据库中的表名  -->
	<class name="com.java.model.Classes" table="t_classes">
	
	<!--主键id name对应实体类的属性,column对应数据库表中的字段 ,generator主键 -->
	<id name="id" column="class_id">
		<generator></generator>
	</id>
	
		<!-- 该对象的基本属性 -->
	<property name="name" column="class_name">
	</property>
	
	
	
   <!--inverse="true" 表示本方classes不进行关联的维护,由另一方进行关联的维护。-->
		        <set name="students" cascade="save-update" inverse="true">
		            <key column="classId"></key>
		            <one-to-many/>
		        </set>
		</class>
</hibernate-mapping>

把数据库数据删除,执行添加数据方法

添加关联方法

发现只执行了学生端s.setC(c);的sql语句,“多”的一段维护主外键关系设置成功

 

四、级联删除

先添加数据

我们想删除班级就可以删除完所有关联的学生,这就需要级联删除

首先先写一个删除方法

	@Test
	public void testDeleteClassCascade(){
		Classes c=(Classes)session.get(Classes.class, Long.valueOf(5));
		session.delete(c);
	}

执行发现报错了,因为班级表关联着学生,所以不能删除班级

实现级联删除只需要在Classes.hbm.xml设置cascade="delete"(在班级端)

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
       <!--班级表class name对应类名,table对应数据库中的表名  -->
	<class name="com.java.model.Classes" table="t_classes">
	
	<!--主键id name对应实体类的属性,column对应数据库表中的字段 ,generator主键 -->
	<id name="id" column="class_id">
		<generator></generator>
	</id>
	
		<!-- 该对象的基本属性 -->
	<property name="name" column="class_name">
	</property>
	
		        <set name="students" cascade="delete" inverse="true">
		            <key column="classId"></key>
		            <one-to-many/>
		        </set>
		</class>
</hibernate-mapping>

执行成功

五、删除学生

重新添加数据

执行删除学生方法

	@Test
	public void testDeleteStudent(){
		Student s=(Student)session.get(Student.class, Long.valueOf(13));
		session.delete(s);
	}

说明学生端是可以直接删除数据,删除学生班级不会删除,班级端要删除数据,所有关联学生都要删除,所以只需要在Classes.hbm.xml设置cascade="delete"

六、一对多双向自身关联关系映射

自身是一也是多

Node.java

package com.java.model;
import java.util.HashSet;
import java.util.Set;

public class Node {

	private long id;
	private String name;
	//父节点 ,自己是“多”的一方,设置一个类
	private Node parentNode;
	//子节点 ,集合,自己是“一”的一方,设置一个集合
	private Set<Node> childNodes=new HashSet<Node>();
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Node getParentNode() {
		return parentNode;
	}
	public void setParentNode(Node parentNode) {
		this.parentNode = parentNode;
	}
	public Set<Node> getChildNodes() {
		return childNodes;
	}
	public void setChildNodes(Set<Node> childNodes) {
		this.childNodes = childNodes;
	}

	
	
}

Node.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

	<class name="com.java.model.Node" table="t_node">
	<id name="id" column="nodeId">
			<generator></generator>
		</id>
		
		<property name="name" column="nodeName"></property>
	     <!--"多"方, 多对一 -->
         <many-to-one name="parentNode" column="parentId"cascade="save-update"></many-to-one>
		
		<!--“一"方 ,一对多 -->
		<set name="childNodes"  inverse="true">
			<key column="parentId"></key>
			<one-to-many/>
		</set>
	 
	</class>


</hibernate-mapping>

hibernate.cfg.xml

<mapping resource="com/java/model/Node.hbm.xml"/>

测试NodeTest.java

package com.java.service;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.java.model.Node;
import com.java.util.HibernateUtil;

public class NodeTest {

	private SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
	private Session session;
	
	@Before
	public void setUp() throws Exception {
		session=sessionFactory.openSession(); // 生成一个session
	    session.beginTransaction(); // 开启事务
	}

	@After
	public void tearDown() throws Exception {
		 session.getTransaction().commit(); // 提交事务
		 session.close(); // 关闭session
	}

	@Test
	public void testSaveMenu() {
		//设置一个父节点
		Node node=new Node();
		node.setName("根节点");
		
		Node subNode1=new Node();
		subNode1.setName("子节点1");
		
		Node subNode2=new Node();
		subNode2.setName("子节点2");
	    
		//字节的添加父节点,实现级联操作
		subNode1.setParentNode(node);
		subNode2.setParentNode(node);
		
		session.save(subNode1);
		session.save(subNode2);
	}
	
	
}

结果截图

今天关于MyBatis查询:多对一映射关系mybatis多对多映射的介绍到此结束,谢谢您的阅读,有关Hibernate中的一对一映射关系、Hibernate单向多对一映射关系01和级联保存和Junit4使用、Hibernate双向一对一映射关系配置代码实例、Hibernate双向多对一映射关系02双向级联,维护主外键关系等更多相关知识的信息可以在本站进行查询。

本文标签: