Hibernate复杂关系映射

本文介绍了Hibernate中的复杂关系映射,包括组成关系与继承关系。组成关系通过组件映射简化了对象模型,而继承关系则提供了多种实现方式,如单表继承、联合表继承和子类表继承。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hibernate复杂的关系映射包含组成关系继承关系

组成关系

         一个表对应一个类维护,当表中出现复杂结构重复结果,就可以将类进行拆分,抽取出单独组件    component,有多个类来维护一张表

例:一个人存在家庭地址和工作地址。

public class Person {

         privateInteger id;

         privateString name;

         //之前需要记录家庭地址的省和市

         //private String homeProvince;

         //private String homeCity;

将家庭地址抽取为一个单独组件 Address

         privateAddress homeAddress;

         //之前需要记录工作地址的省和市

         //private String workProvince;

         //private String workCity;

将家工作地址抽取为一个单独组件 Address

         privateAddress workAddress;

}

地址类,这个类是依存person类的,这两个类是依存一张表的

public class Address {  // 是Person 一个组成部分

         privateString province;

         privateString city;

}


配置文件只需要写person类就可以了,因为address不是一个实体类,没有单独的表。
配置 Person.hbm.xml 
	<hibernate-mapping>
		<class name="cn.itcast.domain.component.Person" table="person" catalog="hibernate3day3">
			<id name="id">
				<generator class="native"></generator>
			</id>
			<property name="name"></property>
			家庭地址的组件配置
			<!-- name 就是Person 类的组件属性的名称
				class 组件类型为address类 -->
			<component name="homeAddress" class="cn.itcast.domain.component.Address">
				<!-- parent 是组件类中所对应实体类的属性名称(谁的组件)-->
				<parent name="person"/>
				<property name="province" column="home_province"></property>
				<property name="city" column="home_city"></property>
			</component>
			工作地址的组件配置
			<component name="workAddress" class="cn.itcast.domain.component.Address">
				<parent name="person"/>
				<property name="province" column="work_province"></property>
				<property name="city" column="work_city"></property>
			</component>
		</class>
	</hibernate-mapping>
在hibernate.cfg.xml中进行映射

常见操作就是单表操作
1)	测试插入
public void testInsert() {
		Session session = HibernateUtil.openSession();
		Transaction transaction = session.beginTransaction();
		//设置人
		Person person = new Person();
		person.setName("小明");
		//设置家庭地址
		Address homeAddress = new Address();
		homeAddress.setProvince("辽宁");
		homeAddress.setCity("沈阳");
		person.setHomeAddress(homeAddress);
		//设置家庭地址
		Address workAddress = new Address();
		workAddress.setProvince("河北");
		workAddress.setCity("秦皇岛");
		person.setWorkAddress(workAddress);
		//保存person,与单表一样
		session.save(person);
		transaction.commit();
		session.close();
	}
2)	测试查询 
	Person person = (Person) session.get(Person.class, 1);
	System.out.println(person);
3)	测试修改 (注意 空指针问题 )
public void testUpdate2() {
		Session session = HibernateUtil.openSession();
		Transaction transaction = session.beginTransaction();
		// 将二号数据 工作城市 修改为 石家庄(但是二号数据之前就没有工作地址)
		Person person = (Person) session.get(Person.class, 2);
		// 可能出现 工作地址为空 , workAddress 为 null,需要添加判断
		if (person.getWorkAddress() == null) {
			Address workAddress = new Address();
			person.setWorkAddress(workAddress);
		}
		person.getWorkAddress().setCity("石家庄");
		transaction.commit();
		session.close();
	}
3) 测试删除 
//删除持久对象与托管对象都行,这里就演示删除托管的对象
		Person person = new Person();
		person.setId(2);
		session.delete(person);

Hibernate 把持久化类的属性分为两种:

    值(value)类型: 没有 OID, 不能被单独持久化, 生命周期依赖于所属的持久化类的对象的生命周期,组                                        件类型就是一种值类型 (简单说就是属性只是目标表一部分数据 (组件映射例如 Ad                                     dress是 Person一个组成部分))

    实体(entity)类型: 有 OID, 可以被单独持久化, 有独立的生命周期(简单说就是属性是存在一个单独表                                      映射(一对多 多对多 ,例如 Order类 关联Customer 类,customer是独立表 ))

 

继承关系

hibernate 描述类之间继承关系,有三种描述方式

第一种  父类和子类使用同一张表,在表中增加一列区分字段,区分数据是父类数据还是子类数据

第二种  父类每个子类都对应单独一张数据表,将公共属性数据放入父类表,将子类个性属性存放到子类表,子类表通过外键引用父类表主键

第三种  父类和每个子类都对应单独一张数据表,表与表之间是无关的,父类表存放父类数据,子类表存放子类数据

 

1使用 subclass方式进行继承映射(父类数据和子类数据在同一张数据表,引入辨别者列 


案例:员工分为钟点工与正式工,都继承员工类
配置 Employee.hbm.xml 
	<hibernate-mapping>
		父类的辨别者列放到class上
		<class name="cn.itcast.domain.subclass.Employee" table="employee" discriminator-value="ee">
			<id name="id">
				<generator class="native"></generator>
			</id>
			<!-- 引入辨别者列 discriminator 列明可以任意指定-->
			<discriminator column="etype"></discriminator>辨别者列必须写在属性之前
			<property name="name"></property>		
			<!-- 配置子类,一个subclass代表一个子类-->
			<subclass name="cn.itcast.domain.subclass.HourEmployee" discriminator-value="he">
				<property name="rate"></property>
			</subclass>
			<subclass name="cn.itcast.domain.subclass.SalaryEmployee" discriminator-value="se">
				<property name="salary"></property>
			</subclass>
		</class>
	</hibernate-mapping>   	

继承映射的编程和单表类似 
1)	测试保存
		// 保存员工
		Employee employee = new Employee();
		employee.setName("张三");
		session.save(employee);
		// 保存钟点工
		HourEmployee employee2 = new HourEmployee();
		employee2.setName("李四");
		employee2.setRate(10d);
		session.save(employee2);
2) 测试查询 
	查询所有钟点工(from HourEmployee),hibernate框架会根据辨别者列where etype='he'来查询。
		//查询子类对象时,hibernate 生成SQL ,根据区分者 列值 进行查询
		Query query = session.createQuery("from HourEmployee");
		List<HourEmployee> employees = query.list();

2、使用joinedsubclass方式 进行继承映射(通用数据在父类表,个性数据在子类表,子类表主键通过外键方式 引用父类表的主键,无需区分者列)
配置 Employee.hbm.xml 
	<hibernate-mapping>
		<class name="cn.itcast.domain.joinedsubclass.Employee" table="employee" >
			<id name="id">
				<generator class="native"></generator>
			</id>
			<property name="name"></property>		
			<!-- 配置子类,使用 joined-subclass 指定表名 -->
			<joined-subclass name="cn.itcast.domain.joinedsubclass.HourEmployee" table="houremployee">
				<!-- 子类表主键就是eid ,本身也是一个外键,引用 employee表主键  -->
				<key column="eid"></key>
				<property name="rate"></property>
			</joined-subclass>
		  <joined-subclass name="cn.itcast.domain.joinedsubclass.SalaryEmployee" table="salaryemployee">
				<key column="eid"></key>
				<property name="salary"></property>
			</joined-subclass>
		</class>
	</hibernate-mapping>    

3、 使用union-subclass 方式进行继承映射(父类和子类数据 分别在各自数据表,数据表直接没有关系,hibernate负责表之间主键连续自增)几乎不用	
	保证多表键主键连续自增 hibernate 通过 increment 策略 
配置Employee.hbm.xml 
	<hibernate-mapping>
		<class name="cn.itcast.domain.unionsubclass.Employee" table="employee" >
			<id name="id">
				<!-- 保证主键在父子表之间 连续自增 -->
				<generator class="increment"></generator>
			</id>
			<property name="name"></property>		
			<!-- 配置子类 使用 union-subclass -->
			<union-subclass name="cn.itcast.domain.unionsubclass.HourEmployee" table="houremployee">
				<property name="rate"></property>
			</union-subclass>
		  <union-subclass name="cn.itcast.domain.unionsubclass.SalaryEmployee" table="salaryemployee">
				<property name="salary"></property>
			</union-subclass>
		</class>
	</hibernate-mapping> 	

三种方式的建议

             首先推荐joninedsubclass 方式(数据库没有冗余),如果子类数据不是很复杂情况,也可以使用s       ubclass方式 ,union-subclass 在开发中 基本不用



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值