上篇文章详细讨论了复合主键的映射原理,对于复合主键映射需要使用<composite-id>标签来标明映射的类属性,并在该标签中添加<key-property>子标签,并且主键列需要实现序列化接口,使用很简单只要学会如何进行映射就可以实现复合映射。接下来讨论组合对象映射,组合映射关系其实是把两个对象的公共部分抽象出来形成一个对象,两个子对象会包含另一个主对像,在配置映射文件时需要使用<component>标签来标明映射关系。
一、组合映射
组合是关联关系的一种特殊情况,是关联关系耦合度最高的一种关系,组合的主对象和子对象拥有相同的生命周期,主对像消亡的话子对象也会消亡。这里使用雇主和用户作为示例,用户和雇主都拥有联系方式属性,如果这里站在对象角度思考的话,常常会把对象模型绘制成为组合的方式,抽象出来一个共同的联系方式类,然后两种人分别包含相应的联系方式对象即可,向应的对象模型时它的对象示例如下图所示:
组合对象模型在生成相应的关系模型后会把对应的子类包含到主表中,所以对应的表结构会将相应的属性生成到对应的表中,相应的表结构如下:
1.1 Employee类及映射文件
在对象模型中Employee和Contact之间拥有包含关系,在编写代码时需要将Contact对象包含在Employee中。对应的映射文件中也需要有Contact对象的映射,需要使用<component>标签来标明组合的对象,并把对象的属性添加到对象标签中。
清单一:Employee.java,类文件中除了基本的属性外还需要分装Contact对象,因为它们之间有一层包含关系。
package com.src.hibernate;
public class Employee {
//id号
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
//名称
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//联系对象
private Contact userContact;
public Contact getUserContact() {
return userContact;
}
public void setUserContact(Contact userContact) {
this.userContact = userContact;
}
}
清单二:Employee.hbm.xml,添加对应的映射文件,映射的组合对象要使用<component>来标明,并在该标签中添加对应的对象属性,具体如下代码:
<?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.src.hibernate.Employee" table="t_employee">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<component name="employeeContact">
<property name="email"/>
<property name="address"/>
<property name="zipCode"/>
<property name="contactTel"/>
</component>
</class>
</hibernate-mapping>
1.2 User类及配置文件
清单三:User.java,它的内容结构和Employee.java的相同,其它的不再多说,看代码:
<pre name="code" class="java">package com.src.hibernate;
public class User {
//id号
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
//姓名
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//联系对象
private Contact userContact;
public Contact getUserContact() {
return userContact;
}
public void setUserContact(Contact userContact) {
this.userContact = userContact;
}
}
清单四:User.hbm.xml,它的内容结构同Employee.hbm.xml内容,主要是<component>标签的使用,很简单,代码如下:
<?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.src.hibernate.User" table="t_user">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<component name="userContact">
<property name="email"/>
<property name="address"/>
<property name="zipCode"/>
<property name="contactTel"/>
</component>
</class>
</hibernate-mapping>
1.3 Contact.java类
该类文件没有什么需要注意的地方,添加基本的属性即可,也不需要为该类配置对应的映射,所以它的内容相当的简单。
package com.src.hibernate;
public class Contact {
//email地址
private String email;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
//住址
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
//邮编号
private String zipCode;
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
//联系电话
private String contactTel;
public String getContactTel() {
return contactTel;
}
public void setContactTel(String contactTel) {
this.contactTel = contactTel;
}
}
1.4 生成结果
经过上面的文件配置后接下来就可以生成相应的数据库表结构了,生成的SQL语句如下:
drop table if exists t_employee生成的数据库表结构如下:
drop table if exists t_user
create table t_employee (id integer not null auto_increment, name varchar(255), email varchar(255), address varchar(255), zipCode varchar(255), contactTel varchar(255), primary key (id))
create table t_user (id integer not null auto_increment, name varchar(255), email varchar(255), address varchar(255), zipCode varchar(255), contactTel varchar(255), primary key (id))
二、数据操作
组合映射得到的表结构是一个完整的表,所以在写入和读取数据时采用最原始的方法就可以实现,这里还使用前几篇文章中用到的测试方法来写入和读取数据,分别是使用save和load方法,具体操作见下文。
2.1 插入数据
这里使用User作为示例,Employee的写入操作同User。在写入数据时需要创建两个对象,一个是联系对象,另外一个是用户对象,在保存时只需要保存用户对象即可,相应的联系对象会连带着保存。
public void testSave1(){
//声明会话对象
Session session=null;
try{
//获取会话对象
session=HibernateUtils.getSession();
//开启会话
session.beginTransaction();
//创建连接对象
Contact userContact=new Contact();
userContact.setAddress("北京市");
userContact.setContactTel("1243435");
userContact.setEmail("123@gamil.com");
userContact.setZipCode("zipCode");
//创建用户对象
User user=new User();
user.setName("zhangsan");
user.setUserContact(userContact);
session.save(user);
//提交会话
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
生成的 SQL 语句:
insert into t_user (name, email, address, zipCode, contactTel) values (?, ?, ?, ?, ?)
查看表结构如下:
2.2读取操作
同样使用User作为示例,Employee的操作同User对象。读取操作相当的简单,代码如下:
public void testLoad1(){
//声明会话对象
Session session=null;
try{
//获取会话对象
session=HibernateUtils.getSession();
//开启会话
session.beginTransaction();
//获取user对象
User user=(User)session.load(User.class, 1);
System.out.println("用户姓名: "+user.getName());
//提交会话
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
生成对应的结果如下:
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.email as email0_0_, user0_.address as address0_0_, user0_.zipCode as zipCode0_0_, user0_.contactTel as contactTel0_0_ from t_user user0_ where user0_.id=?
用户姓名: zhangsan
结语
组合映射需要使用<component>标签,在该标签中添加需要包含的对象,然后Hibernate会把它生成相应的关系模型,相应的写入数据和读取数据的操作也会很简单。组合映射就介绍到这里,下篇文章将会讨论最后一种映射--集合映射。