【Hibernate步步为营】--最后的集合映射

上篇文章详细讨论了组合对象映射的原理,它其实指的是如何将对象模型中的组合关系映射到关系模型中,它是通过使用Hibernate提供的<component>标签来实现的,并需要在该标签中添加对应组合对象的属性,有关组合对象的映射请查看笔者的上篇文章。该篇文章来详细讨论下集合的映射关系,Java的集合有四种分别是Set、Map、List和普通集合,在开发时往往需要将这些集合转化为对应的关系模型,这种集合映射的实现过程就是我们今天要讨论的话题。

一、集合映射

1.1 集合小介

集合映射也是基本的映射,但在开发过程中不会经常用到,所以不需要深刻了解,只需要理解基本的使用方法即可,等在开发过程中遇到了这种问题时能够查询到解决方法就可以了。对应集合映射它其实是指将java中的集合映射到对应的表中,是一种集合对象的映射,在java中有四种类型的集合,分别是Set、Map、List还有普通的数组,它们之间有很大的区别:

Set,不可以有重复的对象,对象是无序的;

List,可以与重复的对象,对象之间有顺序;

Map,它是键值成对出现的;

数组,可以重复,对象之间有顺序。

它们之间的区别决定了在开发时使用哪种集合,通常在开发时会使用Set,它内部的对象是无需的,并可以使用迭代器获取内部对象。这几种集合想要映射到相应的关系模型的话就必须使用Hibernate提供的映射标签,<set>、<list>、<map>、<array>。

1.2 映射小介

继续讨论集合映射的关系模型,集合映射是指一个对象对应着另一个对象集合,在保存时Hibernate会把数据集合保存到相应的表中,并按照自己分配的id把数据保存到数据表中,如果单独为集合分配了新表,那么会将id分配给集合表的id,那么对应的关系表如下图:

1.3 类文件

集合映射是如何通过代码实现的,接下来具体分析。这里把所有的集合封存到一个类中,这个类我们称之为CollectionMapping.java,那么它对应的内部代码如下:

package com.hibernate;

import java.util.List;
import java.util.Map;
import java.util.Set;

@SuppressWarnings("rawtypes")
public class CollectionMapping {

	//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;
	}

	//Set集合
	private Set setValues;
	public Set getSetValues() {
		return setValues;
	}
	public void setSetValues(Set setValues) {
		this.setValues = setValues;
	}

	//List集合
	private List listValues;
	public List getListValues() {
		return listValues;
	}
	public void setListValues(List listValues) {
		this.listValues = listValues;
	}

	//数组集合
	private String[] arrayValues;
	public String[] getArrayValues() {
		return arrayValues;
	}
	public void setArrayValues(String[] arrayValues) {
		this.arrayValues = arrayValues;
	}

	//Map集合
	private Map mapValues;
	public Map getMapValues() {
		return mapValues;
	}
	public void setMapValues(Map mapValues) {
		this.mapValues = mapValues;
	}
}

该类中封装了几种常用的集合,想要转化为关系模型,就必须来看下文的映射。

1.4 集合映射

集合的映射其实相当的简单,只需要添加对应的集合标签,Hibernate分别提供了集合标签<set>、<map>、<list>、<array>,通过使用集中标签来将集合映射为对应的关系表,另外通过添加<key>标签来实现表外键的关联,其它的属性通过使用<element>来添加。

CollectionMapping.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>
	<class name="com.hibernate.CollectionMapping" table="t_collection_mapping">
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="name"/>

		<set name="setValues" table="t_set_values">
			<key column="set_id"></key>
			<element type="string" column="set_value"></element>
		</set>
		<list name="listValues" table="t_list_values">
			<key column="list_id"/>
			<list-index column="list_index"/>
			<element type="string" column="list_value"/>
		</list>
		<map name="mapValues" table="t_map_values">
			<key column="map_id"/>
			<map-key type="string" column="map_key"/>
			<element type="string" column="map_value"/>
		</map>
		<array name="arrayValues" table="t_array_value">
			<key column="array_id"/>
			<index column="array_index" type="integer"></index>
			<element type="string" column="array_value"/>
		</array>
	</class>
</hibernate-mapping>

需要注意的是list标签和array标签,这两种集合内的对象是有顺序的,所以在添加映射标签时需要使用list-index或者index标签来标明对象的顺序,而且在添加子标签时一定要按照顺序添加,也就是说先添加<key>标签,后添加<list-index>标签,最后添加<element>标签,否则的话会出现如下错误:

The content of element type "list" must match "(meta*,subselect?,cache?,synchronize*,comment?,key,(index|list-index),(element|one-to-many|many-to-many|composite-element|many-to-any),loader?,sql-insert?,sql-update?,sql-delete?,sql-delete-all?,filter*)".

1.5 关系模型

将配置好的对象模型转化为相应的关系模型,生成的SQL语句如下:

alter table t_array_value drop foreign key FK2E0DD0C067676B68
alter table t_list_values drop foreign key FKE01EC98BF4FCB03
alter table t_map_values drop foreign key FKD169BA107402B585
alter table t_set_values drop foreign key FK7BB8D04A7E79F8BF
drop table if exists t_array_value
drop table if exists t_collection_mapping
drop table if exists t_list_values
drop table if exists t_map_values
drop table if exists t_set_values
create table t_array_value (array_id integer not null, array_value varchar(255), array_index integer not null, primary key (array_id, array_index))
create table t_collection_mapping (id integer not null auto_increment, name varchar(255), primary key (id))
create table t_list_values (list_id integer not null, list_value varchar(255), list_index integer not null, primary key (list_id, list_index))
create table t_map_values (map_id integer not null, map_value varchar(255), map_key varchar(255) not null, primary key (map_id, map_key))
create table t_set_values (set_id integer not null, set_value varchar(255))
alter table t_array_value add index FK2E0DD0C067676B68 (array_id), add constraint FK2E0DD0C067676B68 foreign key (array_id) references t_collection_mapping (id)
alter table t_list_values add index FKE01EC98BF4FCB03 (list_id), add constraint FKE01EC98BF4FCB03 foreign key (list_id) references t_collection_mapping (id)
alter table t_map_values add index FKD169BA107402B585 (map_id), add constraint FKD169BA107402B585 foreign key (map_id) references t_collection_mapping (id)
alter table t_set_values add index FK7BB8D04A7E79F8BF (set_id), add constraint FK7BB8D04A7E79F8BF foreign key (set_id) references t_collection_mapping (id)

生成的对应的数据库视图如下:

二、数据操作

2.1 数据写入

写入数据操作,将数据写入时需要注意创建数据对象,其中的List、Set、Map需要创建数据对象,将数据对象写入到数据库中,因为它们三者都是对象接口,所以需要创建一个对象,将对象写入到数据库中,具体代码如下:

@SuppressWarnings({ "unchecked", "rawtypes" })
public void testsave(){

	Session session=null;
	try{
		session=HibernateUtils.getSession();
		session.beginTransaction();

		CollectionMapping cm=new CollectionMapping();
		cm.setName("zhangsan");

		Set set=new HashSet();
		set.add("a");
		set.add("b");
		cm.setSetValues(set);

		List list=new ArrayList();
		list.add("list1");
		list.add("list2");
		cm.setListValues(list);

		String[] str=new String[]{"array1","array2"};
		cm.setArrayValues(str);

		Map map=new HashMap();
		map.put("k1","v1");
		map.put("k2", "v2");
		cm.setMapValues(map);

		session.save(cm);
		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
		session.getTransaction().rollback();
	}finally{
		HibernateUtils.closeSession(session);
	}
}

生成的SQL语句如下:

Hibernate: insert into t_collection_mapping (name) values (?)
Hibernate: insert into t_set_values (set_id, set_value) values (?, ?)
Hibernate: insert into t_set_values (set_id, set_value) values (?, ?)
Hibernate: insert into t_list_values (list_id, list_index, list_value) values (?, ?, ?)
Hibernate: insert into t_list_values (list_id, list_index, list_value) values (?, ?, ?)
Hibernate: insert into t_map_values (map_id, map_key, map_value) values (?, ?, ?)
Hibernate: insert into t_map_values (map_id, map_key, map_value) values (?, ?, ?)
Hibernate: insert into t_array_value (array_id, array_index, array_value) values (?, ?, ?)
Hibernate: insert into t_array_value (array_id, array_index, array_value) values (?, ?, ?)

2.2 加载数据

加载数据的方法很简单,它会将表中的数据按照集合加载到对象中,然后只需要获取相应的对象集合即可。

public void testload(){
	Session session=null;
	try{
		session=HibernateUtils.getSession();
		session.beginTransaction();

		CollectionMapping cm=(CollectionMapping)session.load(CollectionMapping.class, 1);

		System.out.println("cm.name= "+cm.getName());
		System.out.println("cm.list= "+cm.getListValues());
		System.out.println("cm.map= "+cm.getMapValues());
		System.out.println("cm.array= "+cm.getArrayValues());
		System.out.println("cm.set= "+cm.getSetValues());

		session.getTransaction().commit();
	}catch(Exception e){
		e.printStackTrace();
		session.getTransaction().rollback();
	}finally{
		HibernateUtils.closeSession(session);
	}
}

生成的结果:

Hibernate: select collection0_.id as id0_0_, collection0_.name as name0_0_ from t_collection_mapping collection0_ where collection0_.id=?
Hibernate: select arrayvalue0_.array_id as array1_0_, arrayvalue0_.array_value as array2_0_, arrayvalue0_.array_index as array3_0_ from t_array_value arrayvalue0_ where arrayvalue0_.array_id=?
cm.name= zhangsan
Hibernate: select listvalues0_.list_id as list1_0_, listvalues0_.list_value as list2_0_, listvalues0_.list_index as list3_0_ from t_list_values listvalues0_ where listvalues0_.list_id=?
cm.list= [list1, list2]
Hibernate: select mapvalues0_.map_id as map1_0_, mapvalues0_.map_value as map2_0_, mapvalues0_.map_key as map3_0_ from t_map_values mapvalues0_ where mapvalues0_.map_id=?
cm.map= {k1=v1, k2=v2}
cm.array= [Ljava.lang.String;@758d8478
Hibernate: select setvalues0_.set_id as set1_0_, setvalues0_.set_value as set2_0_ from t_set_values setvalues0_ where setvalues0_.set_id=?
cm.set= [b, a]

结语

集合映射在开发过程中不会经常用到,但是要做基本的了解,理解这种映射的实现方法,是通过相对应的集合标签来实现的模型转化,很简单。截止到该篇文章,Hibernate基本的映射已经讨论完成,这些映射是对象模型转化为关系模型中经常用到的,文章对映射的用法做了详细的讨论,它们之间的关系还没有做进一步的探讨,所以下篇文章将会对映射做基本的总结展望,对映射进行对比分类。

【Hibernate步步为营】--最后的集合映射

时间: 2024-11-10 01:33:20

【Hibernate步步为营】--最后的集合映射的相关文章

【Hibernate步步为营】--多对多映射详解

上篇文章详细讨论了一对多映射,在一对多映射中单向的关联映射会有很多问题,所以不建议使用如果非要采用一对多的映射的话可以考虑使用双向关联来优化之间的关系,一对多的映射其实质上是在一的一端使用<many-to-one>标签来标明它们之间的关系,另外还需要在一的一端的对象中使用set标明集合映射. 一.单向多对多 仍然按照前几篇的文章格式来讨论,首先来看对象之间的关系,单向的多对多关系是两个对象之间发生的,比如在人和职位之间,一个人可以有多个职位,而且一个职位也可以由多人来负责,所以它们之间就形成了

【Hibernate步步为营】--多对多映射具体解释

上篇文章具体讨论了一对多映射,在一对多映射中单向的关联映射会有非常多问题,所以不建议使用假设非要採用一对多的映射的话能够考虑使用双向关联来优化之间的关系,一对多的映射事实上质上是在一的一端使用<many-to-one>标签来标明它们之间的关系,另外还须要在一的一端的对象中使用set标明集合映射. 一.单向多对多 仍然依照前几篇的文章格式来讨论.首先来看对象之间的关系,单向的多对多关系是两个对象之间发生的,比方在人和职位之间,一个人能够有多个职位,并且一个职位也能够由多人来负责,所以它们之间就形

hibernate 集合映射之有序集合

hibernate 有时候会出现集合映射的情况,一般One-to-many的时候会用到.主要形式为: model: public class TestPerson {       private Long pid;       private String pname;       private String age;       private Set<TestRole> testRole = new HashSet<TestRole>(); -------get() set(

【Hibernate步步为营】--组合映射详解

上篇文章详细讨论了复合主键的映射原理,对于复合主键映射需要使用<composite-id>标签来标明映射的类属性,并在该标签中添加<key-property>子标签,并且主键列需要实现序列化接口,使用很简单只要学会如何进行映射就可以实现复合映射.接下来讨论组合对象映射,组合映射关系其实是把两个对象的公共部分抽象出来形成一个对象,两个子对象会包含另一个主对像,在配置映射文件时需要使用<component>标签来标明映射关系. 一.组合映射 组合是关联关系的一种特殊情况,是

【Hibernate步步为营】--双向关联一对一映射详解(一)

摘要:本文以我自己设计植物大战僵尸碰撞检测算法为例进行分析,浅谈游戏开发中碰撞检测算法.本文所提及的碰撞算法与数据结构也可应用于跑酷等游戏中. 关键优化技术1:只检测逻辑上可能存在碰撞关系的物体.比如植物大战僵尸中,植物发射的子弹只能打击其所在行的僵尸,因此子弹只需遍历检测本行的僵尸,而不是存在场景中的全部僵尸.对于地铁跑酷,奔牛跑酷,吃金币的碰撞检测算法亦是如此. 关键优化技术2:子弹检测碰撞僵尸,或是僵尸检测碰撞子弹,谁检测谁碰撞谁的问题,这个可能跟具体项目息息相关.可以从算法效率,以及设计

【Hibernate步步为营】--单向关联一对一映射(一)

上篇文章对多对一的关联映射做了详细的分析,它在实现上可以有两种方式,并且这两种方式实现也很简单,关键是标签<many-to-one>的使用,它分别指明了多端和一端的映射关系,这种映射关系既是对象模型中的聚合关系.接下来继续讨论关联映射. 一.唯一外键 唯一外键说的是数据库表中的每一行的外键唯一对应着另一张表中的主键,也就是说一个表的主键作为另一张表的外键,并且它们之间的关系是唯一的,这种反应到关系模型中如下图所示: 上图的两个实体表,分别为人和身份证,很明显的一个人对应着一个身份证.身份证作为

【Hibernate步步为营】--双向关联一对一映射详解(二)

很不好意思,有两天时间没有更新博客文章了,不写文章的日子还真是感觉很空洞啊,养成了写文章的恶习想改也改不掉啊.说点题外话,前两天收到一位朋友的私信,邀请笔者写一篇有关OWS的文章,用来研究图标工具的一种技术,很荣幸收到这位朋友的邀请,但是因为这几天开发的项目着急上线所以暂时没有时间去研究,只能等这周末了,利用周末的时间来研究然后更新类似的技术文章. 回到文章的正题,上篇文章讨论了双向主键关联,它其实是一对一主键关联的一种特殊情况,想要实现双向的关联就必须在映射文件的两端同时配置<one-to-o

【Hibernate步步为营】--继承映射详解

上篇文章讨论了多对多映射,在使用多对多映射时重点是使用<many-to-many>标签,并在标签的两端加入外键这样在生成关系时会创建两个关系之间的关系表,通过关系表来维护它们之间的关系,另外对于单向和双向的区别是在映射的哪一端添加标签的问题.在面向对象中很重要的一个特性就是继承,继承实现了代码的复用,而且Hibernate把基本上所有的对象模型进行了映射封装,其中就包括继承映射,接下来就详细讨论. 一.继承映射 继承是面向对象很重要的特性,它实现了代码的服用,在关系模型中同样也有继承关系,这种

【Hibernate步步为营】--详解基本映射

Hibernate进行了分类整合发现其实Hibernate分为三大部分:核心对象.映射.HQL,这三大部分开发过程中最常使用,前几篇讨论了核心对象及对象之间的转换方法,接下来讨论Hibernate的映射使用方法. 一.基本用法 Hibernate一个重要的功能就是映射,它能够在对象模型和关系模型之间转换,是面向对象编程思想提倡使用的,使用映射程序开发人员只需要关心对象模型中代码的编写.对象和关系数据库之间的映射通常是由XML文档来定义的.这个映射文档被设计为易读的,并且可以手动修改.这种映射关系