Hibernate学习---第六节:数组&list&map&set的映射配置

1、实体类,代码如下:

package learn.hibernate.bean;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set; /**
* 持久化类设计
* 注意:
* 持久化类通常建议要有一个持久化标识符(ID)
* 持久化标识符通常建议使用封装类(例如:Integer 因为基本类型存在默认值)
* 持久化类通常建议手动添加一个无参构造函数 (因为有些操作是通过放射机制进行的)
* 属性通常建议提供 getter/setter 方法
* 持久化类不能使用 final 修饰
* 持久化类中如果使用了集合类型数据,只能使用集合所对应的接口类型来声明(List/Map/Set)
* 如下:ArrayList list = new ArrayList(); 不行
* List list = new ArrayList(); 可行
*/
public class Person { private Integer id;
private String name;
private int age;
private int passwork;
private Date birthday;
/**
* 数组 同构类型数据 (效率低)
* 通过 下标 访问数组中的元素
*/
private String[] myArr;
/**
* List
* 通过 下标 访问数组中的元素
*/
private List myList;
/**
* 通过 key 访问value
*/
private Map myMap;
/**
* 只有值本身
*/
private Set mySet; public Person() { } public Person(String name, int age, int passwork, Date birthday) {
super();
this.name = name;
this.age = age;
this.passwork = passwork;
this.birthday = birthday;
} @Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age
+ ", passwork=" + passwork + ", birthday=" + birthday + "]";
} 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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getPasswork() {
return passwork;
}
public void setPasswork(int passwork) {
this.passwork = passwork;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
} public String[] getMyArr() {
return myArr;
} public void setMyArr(String[] myArr) {
this.myArr = myArr;
} public List getMyList() {
return myList;
} public void setMyList(List myList) {
this.myList = myList;
} public Map getMyMap() {
return myMap;
} public void setMyMap(Map myMap) {
this.myMap = myMap;
} public Set getMySet() {
return mySet;
} public void setMySet(Set mySet) {
this.mySet = mySet;
} }

2、映射文件,代码如下:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="learn.hibernate.bean">
<class name="Person" table="t_person">
<id name="id" column="person_id">
<generator class="native"/>
</id>
<property name="name" column="t_name"/>
<property name="age"/>
<property name="passwork"/>
<property name="birthday"/>
<!-- 数组的映射配置 table 可选-->
<array name="myArr" table="t_array">
<!--
t_array 表保存数组中的数据,需要和 t_person 表建立关联关系(一对多),所有需要一个 key
list-index 指定数组下标存储列的映射
element 表示数组中的元素存储列的映射
-->
<key column="id"/>
<list-index column="arr_indexs"/>
<element column="arr_values"/>
</array>
<!-- list 的映射配置 list 和 array 一样-->
<list name="myList">
<key column="id"/>
<list-index column="list_indexs"/>
<element column="list_values"/>
</list>
<!-- map 的映射配置 -->
<map name="myMap">
<!--
map-key 指定 map 集合的 key 数据存储的列映射,并指定类型
element 表示 map 中的元素存储列的映射
-->
<key column="id"/>
<map-key column="map_keys" type="string"/>
<element column="map_values"/>
</map>
<!-- set 的映射配置
set没有下标和 key,只需要元素即可
-->
<set name="mySet">
<key column="id"/>
<element column="set_values"/>
</set>
</class>
</hibernate-mapping>

3、测试代码:

package learn.hibernate.test;

import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set; import learn.hibernate.bean.Person; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; public class TestHibernate { SessionFactory factory = null;
Session session = null;
Transaction tx = null; /**
* 测试之前初始化数据
* @throws Exception
*/
@SuppressWarnings("deprecation")
@Before
public void setUp() throws Exception {
System.out.println("---------初始化数据----------"); Configuration config = new Configuration().configure();
ServiceRegistry sr = new ServiceRegistryBuilder()
.applySettings(config.getProperties()).buildServiceRegistry();
factory = config.buildSessionFactory(sr);
session = factory.openSession();
} /**
* 测试之后释放(销毁)数据
* @throws Exception
*/
@After
public void tearDown() throws Exception {
System.out.println("---------释放数据----------");
if(session.isOpen()){
session.close();
}
} @Test
public void testAdd(){
Person p = new Person("June",22,123456,new Date()); String[] myArr = {"A","B","C","D"}; List myList = new ArrayList();
myList.add("北京");
myList.add("上海");
myList.add("长沙");
myList.add("深圳"); Map myMap = new HashMap();
myMap.put(1, "中国");
myMap.put(2, "湖南");
myMap.put(3, "郴州");
myMap.put(4, "桂阳"); Set mySet = new HashSet();
mySet.add("跑步");
mySet.add("游泳");
mySet.add("篮球"); p.setMyArr(myArr);
p.setMyList(myList);
p.setMyMap(myMap);
p.setMySet(mySet); tx = session.beginTransaction();
session.persist(p);
tx.commit();
}
}

4、测试,会发现报错:

org.hibernate.MappingException: No type name
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:319)
at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:310)
at org.hibernate.mapping.Collection.validate(Collection.java:315)
at org.hibernate.mapping.IndexedCollection.validate(IndexedCollection.java:89)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1362)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1849)
at learn.hibernate.test.TestHibernate.setUp(TestHibernate.java:44)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) java.lang.NullPointerException
at learn.hibernate.test.TestHibernate.tearDown(TestHibernate.java:55)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:33)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

原因是没有给映射文件中的字段指定数据类型

修改映射文件,代码如下:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="learn.hibernate.bean">
<class name="Person" table="t_person">
<id name="id" column="person_id">
<generator class="native"/>
</id>
<property name="name" column="t_name"/>
<property name="age"/>
<property name="passwork"/>
<property name="birthday"/>
<!-- 数组的映射配置 table 可选-->
<array name="myArr" table="t_array">
<!--
t_array 表保存数组中的数据,需要和 t_person 表建立关联关系(一对多),所有需要一个 key
list-index 指定数组下标存储列的映射
element 表示数组中的元素存储列的映射
-->
<key column="id"/>
<list-index column="arr_indexs"/>
<element type="java.lang.String" column="arr_values"/>
</array>
<!-- list 的映射配置 list 和 array 一样-->
<list name="myList">
<key column="id"/>
<list-index column="list_indexs"/>
<element type="java.lang.String" column="list_values"/>
</list>
<!-- map 的映射配置 -->
<map name="myMap">
<!--
map-key 指定 map 集合的 key 数据存储的列映射,并指定类型
element 表示 map 中的元素存储列的映射
-->
<key column="id"/>
<map-key type="java.lang.String" column="map_keys"/>
<element type="java.lang.String" column="map_values"/>
</map>
<!-- set 的映射配置
set没有下标和 key,只需要元素即可
-->
<set name="mySet">
<key column="id"/>
<element type="java.lang.String" column="set_values"/>
</set> <!-- bag 可以重复存放数据,但是修改和删除的时候没有 id 值,所以不知道具体是哪一条,所以会将全部数据删除,重新插入新数据 -->
<!-- <bag name="items" table="t_item">
<key column="id"/>
<element type="java.lang.String" column="name"/>
</bag> --> <!-- bag 的一个升级 数据带ID -->
<!-- <idbag name="items" table="t_item">
<collection-id type="java.lang.String" column="cid">
<generator class="uuid.hex"/>
</collection-id>
<key column="id"/>
<element type="java.lang.String" column="name"/>
</idbag> -->
</class>
</hibernate-mapping>

所有的有序集合类(maps,lists,arrays)都拥有一个由 <key> 和 <index> 组成的主键。这种情况下集合类的更新是非常高效的 — 主键已经被有效的索引,因此当 Hibernate 试图更新或删除一行时,可以迅速找到该行数据。

集合(sets)的主键由 <key> 和其他元素字段构成。对于有些元素类型来说,这很低效,特别是组合元素或者大文本、大二进制字段;数据库可能无法有效的对复杂的主键进行索引。另一方面,对于一对多、多对多关联,特别是合成的标识符来说,集合也可以达到同样的高效性能。( 附注:如果你希望 SchemaExport 为你的 <set> 创建主键,你必须把所有的字段都声明为 not-null="true"。)

<idbag> 映射定义了代理键,因此它总是可以很高效的被更新。事实上,<idbag> 拥有着最好的性能表现。

Bag 是最差的。因为 bag 允许重复的元素值,也没有索引字段,因此不可能定义主键。 Hibernate 无法判断出重复的行。当这种集合被更改时,Hibernate 将会先完整地移除 (通过一个(in a single DELETE))整个集合,然后再重新创建整个集合。因此 Bag 是非常低效的。

请注意:对于一对多关联来说,“主键”很可能并不是数据库表的物理主键。但就算在此情况下,上面的分类仍然是有用的。(它仍然反映了 Hibernate 在集合的各数据行中是如何进行“定位”的。)

文字部分来自:

http://ears.iteye.com/blog/1508557

也可以查看:

http://www.cnblogs.com/otomedaybreak/archive/2012/01/18/2325993.html

上一篇:Hibernate一对一关联映射配置


下一篇:大家一起撸代码之——Hibernate各种主键生成策略与配置详解