Hibernate学习(四):表和表之间的关系

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ScongHW/article/details/82748133

一、 表和表之间的关系

1. 一对多

顾客和商品关系,一个顾客可以选购多件商品。

一对多关系:通过外键建表

在1的一方的实体类中,使用集合表达持有多的一方的引用。

	private Set<Order> orders = new HashSet<Order>();

在多的一方,引入1的一方:

	private Customer customer;

2. 多对多

一个学生可以选择多门课程,一门课程可以有多个学生选择。

多对多关系:使用中间表进行表示

在两个实体类中,使用集合引入多的一方

	private Set<Course> courses  = new HashSet<Course>();
	private Set<Course> courses  = new HashSet<Course>();

3. 一对一

一个公司只有一个总部,一个总部对应一个公司。

一对一关系有两种配置:方式一:外键生成策略    方式二:主键同步策略

二、 一对多操作

1. 一对多关系配置

创建实体类

Customer是1的一方,Order是多的一方。在Customer中使用集合表示持有多的一方

public class Customer {

	private Integer id;
	private String name;
	//在1的一方,使用集合表达持有多的一方的引用
	private Set<Order> orders = new HashSet<Order>();
	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 Set<Order> getOrders() {
		return orders;
	}
	public void setOrders(Set<Order> orders) {
		this.orders = orders;
	}
}
public class Order {

	private Integer id;
	private String name;
	private Customer customer;
	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 Customer getCustomer() {
		return customer;
	}
	public void setCustomer(Customer customer) {
		this.customer = customer;
	}
}

配置映射关系:创建实体类的映射文件

customer.hbm.xml

<hibernate-mapping package="com.scong.domain">
  <class name="Customer" table="t_customer">
		<id name="id" column="id">
			<generator class="native"></generator>
		</id>  
		<property name="name" column="name"></property>

		<!-- 
			Set:表示一对多关系中的集合
				name  : 集合的属性名称
				key   : 用来描述外键
				    column: 外键的值
				one-to-many: 表达Customer 和 Order之间的关系是一对多
					class: 表达关联的另一方的完整类名
		 --> 
		<set name="orders">
			<key column="cid"></key>
			<one-to-many class="Order"/>
		</set>
  </class>
</hibernate-mapping>

order.hbm.xml

<hibernate-mapping package="com.scong.domain">
	<class name="Order" table="t_order">
		<id name="id" column="id">
			<generator class="native"></generator>
		</id>
		<property name="name" column="name"></property>
		<!-- 
			many-to-one: 表示多对一关系
				name:引用属性的名称
				column:外键的列名
				class:引用的customer的完整类名
		 -->
		<many-to-one name="customer" class="Customer" column="cid"></many-to-one>
	</class>
</hibernate-mapping>

测试:

	@Test
	public void fun01(){
		Configuration conf = new Configuration().configure();
		SessionFactory sf = conf.buildSessionFactory();
		Session session = sf.openSession();
		session.beginTransaction();

		Customer c1 = new Customer();
		c1.setName("jack");
		
		Order o1 = new Order();
		o1.setName("啤酒");
		Order o2 = new Order();
		o2.setName("可乐");
		
		c1.getOrders().add(o1);
		c1.getOrders().add(o2);
		
		o1.setCustomer(c1);
		o2.setCustomer(c1);
		
		session.save(c1);
		session.save(o1);
		session.save(o2);

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

2. 关系的维护

 inverse属性:是否放弃对外键的维护,默认值是false

在一对多开发中,1的一方一般都放弃对外键的维护,即<set inverse="true">

在上述Customer映射文件中,若将inverse属性设置为true,则上述测试代码中,可以去掉以下两行代码

		c1.getOrders().add(o1);
		c1.getOrders().add(o2);

同时,也无法直接删除数据库中的t_customer表

3. 级联操作

cascade属性,级联操作。

取值:可以同时配置多项,使用逗号分隔。

  • save-update:级联保存,级联修改。例如保存A的时候,同时保存B
  • delete:级联删除,全部删除。删除A的同时删除B
  • delete-orphan:孤儿删除。当A解除与B的关系时,会将B删除,A仍然存在。
  • all : save-update 和 delete 整合
  • all-delete-orphan : 三个整合

3.1 设置cascade属性的值为save-update时,保存Customer对象的同时将自动级联保存Order对象

	@Test
	public void test01(){
		Configuration conf = new Configuration().configure();
		SessionFactory sf = conf.buildSessionFactory();
		Session session = sf.openSession();
		session.beginTransaction();

		Customer c1 = new Customer();
		c1.setName("jack");
		Order o1 = new Order();
		o1.setName("啤酒");
		Order o2 = new Order();
		o2.setName("可乐");
		c1.getOrders().add(o1);
		c1.getOrders().add(o2);
		o1.setCustomer(c1);
		o2.setCustomer(c1);
		session.save(c1);//设置cascade: save-update,只需要保存c1即可

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

3.2 设置cascade属性的值为delete时,删除Customer数据会将与之相关联的Order数据全部删除

      注意:如果同时设置两个映射文件的cascade属性为delete时,删除它们当中任意一个数据的时候,将同时删除与之关联的所有数据。

		Customer c = (Customer) session.get(Customer.class, 2);
		session.delete(c);  //配置cascade属性的值为:delete,既可级联删除两张表数据

3.3 设置cascade属性的值为delete-orphan时,当解除Customer与Order的关联时,Hibernate将会自动删除Order中的相关数据

		Customer c = (Customer) session.get(Customer.class, 4);
		Iterator<Order> it= c.getOrders().iterator();
		while (it.hasNext()) {
			it.next();
			it.remove(); //解除与Order的关系后,相关的数据将会被删除
		}
		

三、 多对多操作

1. 多对多关系的配置

创建实体类,Student表示学生类,Course表示课程类

Student.java

public class Student {

	private Integer id;
	private String name;
	private Set<Course> courses  = new HashSet<Course>();
	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 Set<Course> getCourses() {
		return courses;
	}
	public void setCourses(Set<Course> courses) {
		this.courses = courses;
	}
}

Course.java

public class Course {

	private Integer id;
	private String name;
	private Set<Student> students = new HashSet<Student>();
	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 Set<Student> getStudents() {
		return students;
	}
	public void setStudents(Set<Student> students) {
		this.students = students;
	}
}

配置映射关系:创建实体类的映射文件

Student.hbm.xml

<hibernate-mapping package="com.scong.domain">
	<class name="Student" table="t_student">
		<id name="id" column="id">
			<generator class="native"></generator>
		</id>
		<property name="name" column="name"></property>
		
		<!-- 
			Set:表示集合
				name  : 集合的属性名称
				table : 配置中间表的表名
			key   : 用来描述外键
				column: 对方引用“我”的外键的值
			one-to-many: 表达关系是多对多
				class: 表达关联的另一方的完整类名
				colum: 对方在中间表的外键名
		 --> 
		
		<set name="courses" table="t_student_course">
			<key column="sid"></key>
			<many-to-many class="Course" column="cid"></many-to-many>
		</set>
	</class>
</hibernate-mapping>

Course.hbm.xml

<hibernate-mapping package="com.scong.domain">
	<class table="t_course" name="Course">
		<id name="id" column="id">
			<generator class="native"></generator>
		</id>
		<property name="name" column="name"></property>
		<set name="students" table="t_student_course">
			<key column="cid"></key>
			<many-to-many class="Student" column="sid"></many-to-many>
		</set>
	</class>
</hibernate-mapping>

配置Hibernate.cfg.xml文件,导入映射文件,进行测试

	@Test
	public void test01(){
		
		Configuration conf = new Configuration().configure();
		SessionFactory sf = conf.buildSessionFactory();
		Session session = sf.openSession();
		session.beginTransaction();

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

结果:数据库中新增三张表,表结构和预想中一致。

2. 级联操作

在多对多关系中,一般只由一方来维护关系,另一方放弃维护,即设置inverse属性为true。在业务上讲,哪方维护关系多点就使用哪一方来维护关系。

多对多关系的级联操作和一对多的级联操作相似,因此只演示级联保存。

1. 设置Student.hbm.xml文件中inverse属性为false,cascade属性为save-update

2. 设置Course.hbm.xml文件中inverse属性为true

3. 测试级联保存

		Student stu1 = new Student();
		stu1.setName("tom");
		Student stu2 = new Student();
		stu2.setName("jack");
		Course c1 = new Course();
		c1.setName("java语言");
		Course c2 = new Course();
		c2.setName("c语言");
		Course c3 = new Course();
		c3.setName("Python语言");
		stu1.getCourses().add(c1);
		stu1.getCourses().add(c2);
		stu1.getCourses().add(c3);
		stu2.getCourses().add(c1);
		stu2.getCourses().add(c2);
		stu2.getCourses().add(c3);
		session.save(stu1);
		session.save(stu2);

4. 结果:保存Student的同时也保存了Course

四、 一对一关系的配置

方式一:外键生成策略

先创建实体类,Company为公司类,Address为地址类

company.java

    public class Company {
    
    	private Integer id;
    	private String name;
    	private Address address;
    	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 Address getAddress() {
    		return address;
    	}
    	public void setAddress(Address address) {
    		this.address = address;
    	}
    }

address.java

    public class Address {
    
    	private Integer id;
    	private String name;
    	private Company company;
    	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 Company getCompany() {
    		return company;
    	}
    	public void setCompany(Company company) {
    		this.company = company;
    	}
    }

配置映射关系:创建实体类的映射文件

Company.hbm.xml

    <hibernate-mapping package="com.scong.domain">
    	<class name="Company" table="t_company">
    		<id name="id" column="id">
    			<generator class="native"></generator>
    		</id>
    		<property name="name" column="name"></property>
    		<!-- 
    			配置一对一关系
    				one-to-one:默认使用主键同步来完成
    				property-ref:指定一对一关联时,指向哪个属性
    		 -->
    		<one-to-one name="address" class="Address" property-ref="company"></one-to-one>
    	</class>
    </hibernate-mapping>

Address.hbm.xml

    <hibernate-mapping package="com.scong.domain">
    	<class name="Address" table="t_address">
    		<id name="id" column="id">
    			<generator class="native"></generator>
    		</id>
    		<property name="name"></property>
    		<!-- unique:外键唯一 -->
    		<many-to-one name="company" class="Company" column="cid" unique="true"></many-to-one>
    	</class>
    </hibernate-mapping>

配置hibernate.cfg.xml文件,将映射文件导入,进行测试

	@Test
	public void test01(){
		
		Configuration conf = new Configuration().configure();
		SessionFactory sf = conf.buildSessionFactory();
		Session session = sf.openSession();
		session.beginTransaction();
		
		Company comp = new Company();
		comp.setName("google");
		Address addr = new Address();
		addr.setName("USA");
		//使用外键生成策略时,外键所在的对象才能维护关系,另一方无法维护
		addr.setCompany(comp);//维护关系
		session.save(comp);
		session.save(addr);
		
		session.getTransaction().commit();
		session.close();
	}

方式二:主键同步策略(推荐使用)

修改映射文件,其他不变

Company.hbm.xml

    <hibernate-mapping package="com.scong.domain">
    	<class name="Company" table="t_company">
    		<id name="id" column="id">
    			<generator class="native"></generator>
    		</id>
    		<property name="name" column="name"></property>
    		<one-to-one name="address" class="Address"></one-to-one>
    	</class>
    </hibernate-mapping>

Address.hbm.xml

    <hibernate-mapping package="com.scong.domain">
    	<class name="Address" table="t_address">
    		<id name="id" column="id">
    			<!-- foreign:既做主键又做外键 -->
    			<generator class="foreign">
    				<!-- 作为外键时引用的是哪个元素 -->
    				<param name="property">company</param>
    			</generator>
    		</id>
    		<property name="name" column="name"></property>
    		<!-- constrained:主键约束 -->
    		<one-to-one name="company" class="Company" constrained="true"></one-to-one>
    	</class>
    </hibernate-mapping>

猜你喜欢

转载自blog.csdn.net/ScongHW/article/details/82748133