hibernate映射学习(三)
2015-06-20 08:37
337 查看
在前面几篇文章中,分别学习了hibernate的关联映射,基本的一对一,一对多,多对 多等都有学习,今天我会给大家带来hibernate中关于"组合映射"和"继承映射"的学习。
## 组合映射##
为什么要学习组合映射,它和一般的映射有什么区别吗??我们先来看一下下面这种情况:
上图,可以看出,user包含了username,address包含了homeaddress,contact包含了qq,phone,这些字段,由于这些属性没有什么必然联系,我们可以将这些字段放入到一个Tuser表里,因为这样的话,对于数据库的维护,已经性能都是有很大的提升。我们可以将Address当做User的属性,将Contact当做Address的属性。这样将所有的属性,只映射到一个Tuser表里,就是组合映射。下面分别来看这三个实体类以及怎么根据这些实体类实现组合映射
Contact.java
public class Contact implements Serializable{ private String qq; private String phone; public String getQq() { return qq; } public void setQq(String qq) { this.qq = qq; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public Contact(String qq, String phone) { super(); this.qq = qq; this.phone = phone; } public Contact() { super(); } }
Address.java
public class Address implements Serializable { private String homeAddress; private Contact contact = null; public Contact getContact() { return contact; } public void setContact(Contact contact) { this.contact = contact; } public String getHomeAddress() { return homeAddress; } public void setHomeAddress(String homeAddress) { this.homeAddress = homeAddress; } public Address(String homeAddress, Contact contact) { super(); this.homeAddress = homeAddress; this.contact = contact; } public Address() { super(); } }
UserInfo.java
package com.mydb.entity; import java.io.Serializable; public class UserInfo implements Serializable { private int userId; private String userName; private String userPass; private Address address = null; public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPass() { return userPass; } public void setUserPass(String userPass) { this.userPass = userPass; } @Override public String toString() { return "UserInfo [userId=" + userId + ", userName=" + userName + ", userPass=" + userPass + "]"; } }
可以看到这里,我是将contact变成Address的属性,再将address变成User的属性。此时,UserInfo对应的映射文件内容如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <!-- name="全类名" table="表名" --> <class name="com.mydb.entity.UserInfo" table="userinfo"> <!-- name="属性名" column="主键"--> <id name="userId" column="uid"> <!-- 主键的生成策略:native(主键自增),assigned(指派) --> <generator class="increment"></generator> </id> <component name="address"> <property name="homeAddress"></property> <component name="contact"> <property name="phone"></property> <property name="qq"></property> </component> </component> <!-- name="属性名" column="字段名" --> <property name="userName" column="uname"></property> <property name="userPass" column="upass"></property> </class> </hibernate-mapping>
可以看到映射到的userinfo表的主键是自增的,对于组合映射,将address映射到user中,将contact映射到address中,是这样做的:
<component name="address"> <property name="homeAddress"></property> <component name="contact"> <property name="phone"></property> <property name="qq"></property> </component> </component>
我们通过component标签来实现组合映射。接下来编写测试类:
//解析hibernate.cfg.xml文件 Configuration cfg = new Configuration().configure(); //创建SessionFactory(创建连接池) SessionFactory factory = cfg.buildSessionFactory(); //创建session Session session = factory.openSession(); UserInfo userInfo = new UserInfo(); userInfo.setUserName("gaga"); userInfo.setUserPass("123456"); userInfo.setAddress(new Address("深圳",new Contact("456754433","12367544554"))); //创建以及开启事物对象 Transaction transaction = null; try { transaction = session.beginTransaction(); session.save(userInfo); transaction.commit(); } catch (HibernateException e) { if (transaction != null) { transaction.rollback(); } e.printStackTrace(); } finally { if (session != null) { session.close(); } }
这里,我存储了一个userinfo到映射的userinfo表里,此时看下userinfo表都有哪些字段:
此时我们就将address类和contact以及userinfo类中的属性都映射到一个表里边了。
继承映射
为什么要有继承映射,首先我们咋面向对象中,经常会用到继承这种方式来实现代码复用,那么如果是一个实体类,有继承关系,但是在数据库表中是没有这样的继承关系的,在数据库当中,只有关联,并且继承是有多态的,那么当我们从数据库当中,查找出来的数据,如何确保封装成正确的格式呢??由此继承映射就应运而生吧。下面看下我们的实体类:
Animal.java
public class Animal implements Serializable { private int animalId; public int getAnimalId() { return animalId; } public void setAnimalId(int animalId) { this.animalId = animalId; } private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
Pig.java
public class Pig extends Animal implements Serializable { private int weight;//重量 public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } }
Dog.java
public class Dog extends Animal implements Serializable { private String dark; public String getDark() { return dark; } public void setDark(String dark) { this.dark = dark; } }
可以看到dog和pig这两个类,有一个共同的属性name,又各自有自己的属性。映射文件如下:
<hibernate-mapping package="com.mydb.entity.jicheng"> <!-- name="全类名" table="表名" --> <class name="Animal" table="t_animal"> <!-- name="属性名" column="主键"--> <id name="animalId"> <!-- 主键的生成策略:native(主键自增),assigned(指派) --> <generator class="increment"></generator> </id> <discriminator column="discriminator" type="string"></discriminator> <property name="name"></property> <subclass name="Dog" discriminator-value="D"> <property name="dark"></property> </subclass> <subclass name="Pig" discriminator-value="P"> <property name="weight"></property> </subclass> </class> </hibernate-mapping>
说明一下,subclass标签指定继承自animal的子类,discriminator是用来正确封装我们查询的数据到指定子类,discriminator是在animal表中增加一个列,用来存储每一行是pig类型还是dog类型的数据。可以看到如果是Dog类型的数据,则该列的值是”D”,如果是pig类型的数据,那么该列的值是”P”.
编写测试类:
//解析hibernate.cfg.xml文件 Configuration cfg = new Configuration().configure(); //创建SessionFactory(创建连接池) SessionFactory factory = cfg.buildSessionFactory(); //创建session Session session = factory.openSession(); Dog dog = new Dog(); dog.setName("哈士奇"); dog.setDark("wangwang"); Pig pig = new Pig(); pig.setName("胖猪"); pig.setWeight(300); //创建以及开启事物对象 Transaction transaction = null; try { transaction = session.beginTransaction(); session.save(pig); session.save(dog); transaction.commit(); } catch (HibernateException e) { if (transaction != null) { transaction.rollback(); } e.printStackTrace(); } finally { if (session != null) { session.close(); } }
上面的测试方法分别给t_animal表中存储了一个Dog和Pig这两个类型的数据,下面看看数据库的内容:
可以看到在t_animal表格当中已经增加了一列discirminator,用来区分该类存储的类型的具体子类。
此时当我再次通过session查询的时候,就会查询出正确的类型,可以看到表格里边id=1的行存储了一个Pig类型的数据:
Pig pig = (Pig) session.get(Animal.class,1); System.out.println(pig.getName());
此时类型将会正确的转换,但是如果此时强制将Pig转换成Dog类型,hibernate将会抛出下面的异常:
基于接口的隐式多态查询
hibernate同样提供查询实现某一个接口的所有具体的实体类,我这里新建一个接口:public interface AnimalInterface { }
然后让Pig和Dog这两个类同时实现该接口,接下来利用hql来实现基于接口的隐式多态查询:
Session session = factory.openSession(); String hql = "from com.mydb.entity.jicheng.AnimalInterface"; Query query = session.createQuery(hql); List list = query.list(); for (Object object : list) { if (object instanceof Dog) { System.out.println(((Dog) object).getName()+"叫声:"+((Dog) object).getDark()); } else if (object instanceof Pig) { System.out.println(((Pig) object).getName()+"体重是:"+((Pig) object).getWeight()); } }
继承映射(每个子类一张表)
接下来给大家介绍第二种继承映射,上面继承映射的实现方式是将所有的子类放入到一张表中来存储,然后通过discriminator标签来实现多台查询时候的正确转型,下面带大家实现第二种继承映射即:每一个子类映射一张表,同样是animal,dog,pig这三个类,只需要这样配置映射文件即可:<hibernate-mapping package="com.mydb.entity.jicheng"> <!-- name="全类名" table="表名" --> <class name="Animal" table="t_animal"> <!-- name="属性名" column="主键" --> <id name="animalId"> <!-- 主键的生成策略:native(主键自增),assigned(指派) --> <generator class="increment"></generator> </id> <joined-subclass name="Dog" table="t_dog"> <key column="aid"></key> <property name="dark"></property> </joined-subclass> <joined-subclass name="Pig" table="t_pig"> <key column="aid"></key> <property name="weight"></property> </joined-subclass> </class> </hibernate-mapping>
joined-subclass标签,name属性填写子类的类名,table填写子类映射到的表名称,
<key column="aid"></key>表示关联animal表的外键。此时会在数据库中生成”t_animal”,”t_dog”,”t_pig”这三个表:
t_animal
t_dog
t_pig
hibernate中set集合映射
在之前一对一,和多对多的映射中,我们利用set集合来映射,但是如果是基本的类型,应该怎么办呢??我如我一个User有很多张图片:比如我现在给userinfo中增加一个
private Set<String>photoes = new HashSet();
并且设置get和set方法,此时配置文件需要这么写:
<set name="photoes" table="t_photo"> <key column="photoid"></key> <element column="photoAddrs" type="string"></element> </set>
table=”t_photo”表示photo将单独映射到一张表里,column=”photoid”表示所映射到的”t_photo”表所对应userinfo表的外键。
可以看到此时photo表中的photoid是userinfo表中的外键。
那么问题有来了,如果是对象类型的set集合呢??比如我在userinfo类中在增加这样一个set集合:
private Set<Contact>contacts = new HashSet<>();
并提供get和set方法。此时需要这样配置:
<set name="contacts" table="t_contacts"> <key column="contact_id"></key> <composite-element class="com.mydb.entity.Contact"> <property name="phone"></property> <property name="qq"></property> </composite-element> </set>
ok,关于hibernate关联映射的学习就到这里了,希望大家能够喜欢。
相关文章推荐
- 图的存储
- 测试帖
- Ubuntu14.04 VIM的插件管理
- [BZOJ 2431] [HAOI2009] 逆序对数列
- C++ 基于Dijkstra最短路搜索的Ford Fulkson最大流算法
- 20150620文本自动滚动效果
- 黑马程序员--面向对象细节知识点--3rd day
- 补第一阶段冲刺站立会议9(原5月21日)
- C注意,使用的语言字符串
- 补第一阶段冲刺站立会议8(原5月20日)
- muduo网络图书馆评测
- 循环广告位组件的实现
- 补第一阶段冲刺站立会议7(应发表日期5月19日)
- 线程和进程
- Java知多少(98)Graphics类的绘图方法
- Win10 Build 10147批量截图:加入不少新图标
- HTML5系列一(属性概述)
- iOS 视图生命周期
- WCF医院管理系统技术解析(十一)医生体检收入查询(带一定判断的导出Excel)
- 练习代码(二)隐藏具体实现