Hibernate之关联关系映射

一、一对多

Dempartment {
	private int id;
	private String name;

	private Set<Employee> employees = new HashSet<Employee>();
}
Employee {
	private int id;
	private String name;

	private Dempartment department;
}
---Employee.hbm.xml
<?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="pde.ams.onetomany">

	<class name="Employee" table="employee">
		<id name="id">
			<generator class="native" />
		</id>
		<property name="name"></property>

		<many-to-one name="department" column="departmentId" class="Dempartment"></many-to-one>
	</class>
</hibernate-mapping>
---Dempartment.hbm.xml
<?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="pde.ams.onetomany">

	<class name="Dempartment" table="dempartment">
		<id name="id">
			<generator class="native" />
		</id>
		<property name="name"></property>

     <!-- employees属性 是Employees对象 Dempartment与Employees的一对多的关系 -->
		<set name="employees">
			<key column="departmentId"></key>
			<one-to-many class="Employee"/>
		</set>
	</class>
</hibernate-mapping>
package pde.ams.onetomany;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

/**
 * @author 作者 macx:
 * @version 创建时间:2018年4月29日 下午1:40:06 类说明
 */
public class App {

	private static SessionFactory sessionFactory = new Configuration()//
			.configure()//
			.addClass(Dempartment.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件)
			.addClass(Employee.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件)
			.buildSessionFactory();

	@Test
	public void saveUser() {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// ---------------------------------------

		// 创建对象
		Dempartment department = new Dempartment();
		department.setName("开发部1");

		Employee employee1 = new Employee();
		employee1.setName("张三");

		Employee employee2 = new Employee();
		employee2.setName("李四");

		// 关联起来
		employee1.setDepartment(department);
		employee2.setDepartment(department);
		department.getEmployees().add(employee1);
		department.getEmployees().add(employee2);

		// 保存
		session.save(department); // 保存部门
		session.save(employee1);
		session.save(employee2);

		// ---------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	@Test
	public void getUser() {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// ---------------------------------------

		// 获取部门,并显示关联的员工信息
		Dempartment department = (Dempartment) session.get(Dempartment.class, 29);
		System.out.println("部门名称:" + department.getName());
		System.out.println("关联的员工:" + department.getEmployees());

		// // 获取员工,并显示关联的部门信息
		 Employee employee = (Employee) session.get(Employee.class, 1);
		 System.out.println("员工姓名:" + employee.getName());
		 System.out.println("所属的部门:" + employee.getDepartment());

		// ---------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	// 移除关联关系
	@Test
	public void testRemoveRelation() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// ---------------------------------------

		// // 让员工不再属于原部门
		// Employee employee = (Employee) session.get(Employee.class, 1);
		// employee.setDepartment(null);

		// 让Department不与任何Employee关联
		Dempartment department = (Dempartment) session.get(Dempartment.class, 26);
		department.getEmployees().clear();

		// ---------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	// 删除(测试对关联对象的影响)
	@Test
	public void testDelete() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// ---------------------------------------

		// // 删除员工,对关联的部门没有影响
		// Employee employee = (Employee) session.get(Employee.class, 1);
		// session.delete(employee);

		// // 删除部门,如果有关联的员工,则会:
		// 1,inverse="false",这也是默认值,表示本方能维护关联关系(外键),这时会先把所有关联的员工都移除关系,再删除自己。
		// 2,inverse="true",表示本方不能维护关联关系(外键),就会直接删除自己,这时会抛异常。
		Dempartment department = (Dempartment) session.get(Dempartment.class, 2);
		session.delete(department);

		// ---------------------------------------
		session.getTransaction().commit();
		session.close();
	}

}

二、多对多

public class Student {
	private int id;
	private String name;

	private Set<Teacher> teacherSet = new HashSet<Teacher>();
}
public class Teacher {
	private int id;
	private String name;

	private Set<Student> studentSet = new HashSet<Student>();
}
package pde.ams.manytomany;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

/**
 * @author 作者 macx:
 * @version 创建时间:2018年4月29日 下午1:40:06 类说明
 */
public class App {

	private static SessionFactory sessionFactory = new Configuration()//
			.configure()//
			.addClass(Teacher.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件)
			.addClass(Student.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件)
			.buildSessionFactory();

	@Test
	public void saveUser() {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// ---------------------------------------

		// 创建对象
		Teacher teacher1 = new Teacher();
		teacher1.setName("赵老师");

		Teacher teacher2 = new Teacher();
		teacher2.setName("冯老师");

		Student student1 = new Student();
		student1.setName("张三");

		Student student2 = new Student();
		student2.setName("李四");

		// 关联起来
		teacher1.getStudentSet().add(student1);
		teacher1.getStudentSet().add(student2);
		teacher2.getStudentSet().add(student1);
		teacher2.getStudentSet().add(student2);

		student1.getTeacherSet().add(teacher1);
		student1.getTeacherSet().add(teacher2);
		student2.getTeacherSet().add(teacher1);
		student2.getTeacherSet().add(teacher2);

		// 保存
		session.save(teacher1);
		session.save(teacher2);
		session.save(student1);
		session.save(student2);

		// ---------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	@Test
	public void getUser() {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// ---------------------------------------

		// 获取一个Student,并显示相关的Teacher信息
		Student student = (Student) session.get(Student.class, 3);
		System.out.println("学生的姓名:" + student.getName());
		System.out.println("此学生的老师:" + student.getTeacherSet());

		// ---------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	// 移除关联关系
	@Test
	public void testRemoveRelation() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// ---------------------------------------

		// 获取一个Student,并移除与所有老师的关联
		Student student = (Student) session.get(Student.class, 5);
		student.getTeacherSet().clear();

		// Teacher teacher = (Teacher) session.get(Teacher.class, 5);
		// teacher.getStudentSet().clear();
		// ---------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	// 删除(测试对关联对象的影响)
	@Test
	public void testDelete() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// ---------------------------------------

		// 删除一个Student,如果有关联的老师,则:
		// 如果inverse="false",表示可以维护关联关系,这时会先删除关系,再删除自己。
		// 如果inverse="true",表示不可以维护关联关系,这时会直接删除自己,会有异常。
		Student student = (Student) session.get(Student.class, 5);
		session.delete(student);

		// ---------------------------------------
		session.getTransaction().commit();
		session.close();
	}

}

三、级联  cascade

1、概念

当hibernate持久化一个临时对象时,在默认情况下,他不会自动持久化所关联的其他临时对象,而是会抛出TransientObjectException.如果设定many-to-one元素的cascade属性为save-update的话,可实现自动持久化所关联的对象。

级联指的是当主控方执行操作时,关联对象(被动方)是否同步执行同一操作。

2、级联风格

每个 Hibernate session 的基本操作 — 包括 persist(), merge(), saveOrUpdate(), delete(),lock(), refresh(),evict(), replicate() — 都有对应的级联风格(cascade style)。这些级联风格(cascade style)风格分别命名为persist, merge, save-update,delete, lock, refresh, evict, replicate。

级联风格

Session中的方法

persist

persist()

merge

merge()

save-update

save()、update()、saveOrUpdate()

delete

delete()

lock

lock()

refresh

refresh()

evict

evict()

replicate

replicate()

如果你希望一个操作被顺着关联关系级联传播,你必须在映射文件中指出这一点。

指定级联风格:

<one-to-one name="person" cascade="persist"/>

级联风格(cascadestyle)是可组合的:

<one-to-one name="person" cascade="persist,delete"/>

你可以使用 cascade="all" 来指定全部操作都顺着关联关系级联(cascaded)。默认值是cascade="none",即任何操作都不会被级联(cascaded)。

delete-orphan

A special cascade style, delete-orphan, applies only toone-to-many associations, and indicates that the delete() operation should beapplied to any child object that is removed from the association.

在对象–关系映射文件中, 用于映射持久化类之间关联关系的元素, 如<set>,<many-to-one> 和 <one-to-one> 都有一个 cascade属性。

四、一对一
public class Person {
	private int id;
	private String name;
	private IdCard idCard;
}
public class IdCard {
	private int id;
	private String number;
	private Person person;
}
---IdCard.hbm.xml
<?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="pde.ams.onetoone">

	<class name="IdCard" table="idCard">
		<id name="id">
			<generator class="native" />
		</id>
		<property name="number"></property>

		<!-- person属性,表达IdCard与Person的一对一。 采用基于外键的一对一映射方式。 有外键方,就是多对一加上惟一性约束。 -->
		<many-to-one name="person" class="Person" column="personId"
			unique="true" cascade="save-update,delete"></many-to-one>

	</class>
</hibernate-mapping>
---Person.hbm.xml
<?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="pde.ams.onetoone">

	<class name="Person" table="person">
		<id name="id">
			<generator class="native" />
		</id>
		<property name="name"></property>
		<!-- idCard属性,表达的是Person与IdCard的一对一。 采用基于外键的一对一映射方式。 无外键方,使用one-to-one,property-ref写的是对方映射中表达此一对一的属性 -->
		<one-to-one name="idCard" class="IdCard" property-ref="person" cascade="delete"></one-to-one>
	</class>
</hibernate-mapping>
public class App {

	private static SessionFactory sessionFactory = new Configuration()//
			.configure()//
			.addClass(Person.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件)
			.addClass(IdCard.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件)
			.buildSessionFactory();

	@Test
	public void saveUser() {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// ---------------------------------------
		Person p = new Person();
		p.setName("张三");

		IdCard idcard = new IdCard();
		idcard.setNumber("12345678");

		// 关联起来
		// 使用基于外键的一对一时:Person是无外键方,不可以维护关联关系
		// 使用基于外键的一对一时:IdCard是有外键方,可以维护关联关系
		// 使用基于主键的一对一时:也是只有有外键方可以保存关联关系
		p.setIdCard(idcard);
		idcard.setPerson(p);
		// 保存
		// session.save(p);
		session.save(idcard);
		// ---------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	@Test
	public void getUser() {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// ---------------------------------------
		Person person = (Person) session.get(Person.class, 1);

		IdCard id = (IdCard) session.get(IdCard.class, 1);
		System.out.println(id);
		System.out.println(id.getNumber());
		System.out.println(id.getPerson().getName());
		// ---------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	// 移除关联关系
	@Test
	public void testRemoveRelation() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// ---------------------------------------
		IdCard id = (IdCard) session.get(IdCard.class, 1);
		id.setPerson(null);

		session.save(id);
		// ---------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	// 删除(测试对关联对象的影响)
	@Test
	public void testDelete() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// ---------------------------------------
		// IdCard id = (IdCard) session.get(IdCard.class, 1);
		// session.delete(id);

		Person p = (Person) session.get(Person.class, 2);
		session.delete(p);
		// ---------------------------------------
		session.getTransaction().commit();
		session.close();
	}

五、继承关系映射

1、映射一(同一表中)

public class Article {
	private Integer id;
	private String title;
	private String content;
}
public class Reply extends Article{
	private int floor; // 楼层
}
public class Topic extends Article {
	private int type; // 主题类型,比如精华帖、置顶帖等等
}
---Article.hbm.xml
<?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="pde.ams.extend_1">
	<!-- 
		继承结构映射:整个继承结构一张表
		discriminator-value属性:指定哪个值表示当前类型
	 -->
	<class name="Article" table="article" discriminator-value="Article"> 
		<id name="id">
			<generator class="native"></generator>
		</id>
		<!-- 指定一个用于鉴别是什么类型的列 -->
		<discriminator column="_class" type="string"></discriminator>
		<property name="title"></property>
		<property name="content" type="text" length="5000"></property>
		
		<!-- 子类:Topic -->
		<subclass name="Topic" discriminator-value="Topic">
			<property name="type"></property>
		</subclass>

		<!-- 子类:Reply -->
		<subclass name="Reply" discriminator-value="Reply">
			<property name="floor"></property>
		</subclass>	
	</class>
</hibernate-mapping>

2、映射二(三个不同表)

<?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="pde.ams.extend_2">
	
	<!-- 
		继承结构映射:每个类一张表,抽象也对应表。
		每个类的映射中都要写表名。
		子类映射中要指定一个外键列<key column="id"></key>
	 -->
	<class name="Article" table="article"> 
		<id name="id">
			<generator class="native"></generator>
		</id>
		<property name="title"></property>
		<property name="content" type="text" length="5000"></property>
		
		<!-- 子类:Topic -->
		<joined-subclass name="Topic" table="topic">
			<key column="id"></key>
			<property name="type"></property>
		</joined-subclass>

		<!-- 子类:Reply -->
		<joined-subclass name="Reply" table="reply">
			<key column="id"></key>
			<property name="floor"></property>
		</joined-subclass>
		
	</class>

</hibernate-mapping>

3、映射三

<?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="pde.ams.extend_3">
	
	<!-- 
		继承结构映射:每个具体类一张表,抽象不对应表。
		如果类是抽象的,就要写上abstract="true",这样就不会创建表了,也不需要table属性了。
		这时不能使用identity主键生成策略,因为继承结构映射要求在整个继承结构中,所有数据的主键值不能重复。
	 -->
	<class name="Article" table="article"> 
		<id name="id">
			<!-- increment策略,由Hibernate维护的主键增长 -->
			<generator class="increment"></generator>
		</id>
		<property name="title"></property>
		<property name="content" type="text" length="5000"></property>
		
		<!-- 子类:Topic -->
		<union-subclass name="Topic" table="topic">
			<property name="type"></property>
		</union-subclass>

		<!-- 子类:Reply -->
		<union-subclass name="Reply" table="reply">
			<property name="floor"></property>
		</union-subclass>
		
	</class>

</hibernate-mapping>

猜你喜欢

转载自blog.csdn.net/weixin_40931184/article/details/80208015