hibernate学习笔记12--Hibernate中使用的集合类型
2013-06-02 16:03
525 查看
关联关系总结:
如何考虑hibernate处理对象之间的关联关系的底层细节时,可以从两方面进行思考
(1)如何将对象之间的关联关系保存到数据库中
(2)如何检索出关联的对象(主语句要看sql)
(映射文件id缺省的情况下)
一对一:1条sql
多对一或是一对多:2条sql
多对多:3条sql
三、bag标签必须与list接口对相应
与list的标签时的表结构相比,少了list-index的这一列。从而减少了内存开销
employee 表结构
Name Type Nullable Default Comments
--------- ------------- -------- ------- --------
ID NUMBER(10)
NAME VARCHAR2(255)
DEPART_ID NUMBER(10)
映射文件:
测试程序:
四、Map
实体映射文件:
Map是键值对的形式,key不重复
SQL> desc department;
Name Type Nullable Default Comments
---- ------------- -------- ------- --------
ID NUMBER(10)
NAME VARCHAR2(255)
SQL> desc employee;
Name Type Nullable Default Comments
--------- ------------- -------- ------- --------
ID NUMBER(10)
NAME VARCHAR2(255)
DEPART_ID NUMBER(10)
五、数组array
实体映射文件:
SQL> desc department;
Name Type Nullable Default Comments
---- ------------- -------- ------- --------
ID NUMBER(10)
NAME VARCHAR2(255)
SQL> desc employee;
Name Type Nullable Default Comments
----------- ------------- -------- ------- --------
ID NUMBER(10)
NAME VARCHAR2(255)
DEPART_ID NUMBER(10)
ORDER_COLUM NUMBER(10) Y
六、 hibernate中集合的选择:
一般都选择set集合,配置方便,而且不允许重复也符合一般的业务逻辑。
如果就是想使用list集合,不想保证正确顺序记录时用bag标签,想保证记录顺序时list标签
array一般很少用,因为数组的尺寸需要掌控,很容易造成数组越界,不便于管理
七、关于类型的一个小实验
第一步:将domain中的属性Set类型修改为HashSet类型和修改相关的setter和getter方法
public HashSet<Employee> getEmps() {
return emps;
}
第二步:
HashSet hs =(HashSet)depart.getEmps();
此时报错:
Exception in thread "main" java.lang.ClassCastException: org.hibernate.collection.internal.PersistentSet cannot be cast to java.util.HashSet
at cn.itcast.RelationalMapping.One2many.add2(One2many.java:147)
at cn.itcast.RelationalMapping.One2many.main(One2many.java:26)
分析:Hibernate为了方便对集合懒加载操作,在顶层对所有的jdk中的集合进行了改写,所以只要以保存之后再取出来,hibernate已经对数据类型进行转换
所以domain定义时属性不能定义成具体的类,而是定义成接口(如定义成Set而不是HashSet)。
否则无法再hibernate中运行报类型异常
2013-6-2 15:44:18 org.hibernate.property.BasicPropertyAccessor$BasicSetter set
ERROR: HHH000123: IllegalArgumentException in class: cn.itcast.domain.Department, setter method of property: emps
2013-6-2 15:44:18 org.hibernate.property.BasicPropertyAccessor$BasicSetter set
ERROR: HHH000091: Expected type: java.util.HashSet, actual value: org.hibernate.collection.internal.PersistentSet
Exception in thread "main" org.hibernate.PropertyAccessException: IllegalArgumentException occurred while calling setter of cn.itcast.domain.Department.emps
at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:119)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.setPropertyValues(AbstractEntityTuplizer.java:710)
at org.hibernate.tuple.entity.PojoEntityTuplizer.setPropertyValues(PojoEntityTuplizer.java:371)
at org.hibernate.persister.entity.AbstractEntityPersister.setPropertyValues(AbstractEntityPersister.java:4509)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:275)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:192)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:135)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:206)
at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:55)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:191)
at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:49)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:764)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:756)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:752)
at cn.itcast.RelationalMapping.One2many.add2(One2many.java:142)
at cn.itcast.RelationalMapping.One2many.main(One2many.java:26)
Caused by: java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:65)
... 16 more
因为org.hibernate.collection.internal.PersistentSet 是实现了Set接口的,到但是不是从HashSet中继承过来的
结论:在持久化类中(domain类中),类中属性(成员变量)定义成接口不要定义成具体的类(如定义成Set而不是HashSet)。
剩余相关代码:
如何考虑hibernate处理对象之间的关联关系的底层细节时,可以从两方面进行思考
(1)如何将对象之间的关联关系保存到数据库中
(2)如何检索出关联的对象(主语句要看sql)
(映射文件id缺省的情况下)
一对一:1条sql
多对一或是一对多:2条sql
多对多:3条sql
对象集合使用类的一部分 单个属性,来取代一对多(比如只要员工类的名字) 一、set特性:没有顺序,不允许元素重复
表结构: SQL> desc department; Name Type Nullable Default Comments ---- ------------- -------- ------- -------- ID NUMBER(10) NAME VARCHAR2(255) SQL> desc employee; Name Type Nullable Default Comments --------- ------------- -------- ------- -------- ID NUMBER(10) NAME VARCHAR2(255) DEPART_ID NUMBER(10)
映射文件:
<set name="emps" >
<key column="depart_id"></key><!-- 告诉hibernate按照什么字段检索employee表数据,必须和employee.hbm.xnml中的外键定义一样-->
<one-to-many class="Employee"></one-to-many> <!--告诉hibernate集合set中装什么类型 -->
</set> 二、list特性:有顺序的,可以元素重复,但是索引不可重复 在employee表中会由hibernate根据Department.hbm.xml一对多的映射关系添加一字段,用于记录是加入的第几个员工 table employee结构 Name Type Nullable Default Comments --------- ------------- -------- ------- -------- ID NUMBER(10) NAME VARCHAR2(255) DEPART_ID NUMBER(10) ORDER_COL NUMBER(10) Y
映射文件:
<list name="emps"> <key column="depart_id"/> <list-index column="order_col"/>因为List是有顺序的,hibernate通过这个标签记录员工是第几个加进来的 <one-to-many class="Employee" /> </list> list总结:对于有些时候我们是不需要保存list的加入顺序,因为也会消耗不少的内存资源。 此时不需保存顺序时,可以在映射文件使用bag标签,jdk没有特别与之对应的集合,但是使用了bag标签,domain则必须是list相对应才可使用
三、bag标签必须与list接口对相应
与list的标签时的表结构相比,少了list-index的这一列。从而减少了内存开销
employee 表结构
Name Type Nullable Default Comments
--------- ------------- -------- ------- --------
ID NUMBER(10)
NAME VARCHAR2(255)
DEPART_ID NUMBER(10)
映射文件:
<bag name="emps"> <key column="depart_id"/> <one-to-many class="Employee" /> </bag>
测试程序:
package cn.itcast.RelationalMapping; import java.util.ArrayList; import java.util.List; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import cn.itcast.dao.HibernateUtil; import cn.itcast.domain.Department; import cn.itcast.domain.Employee; /** * 一对多测试类 * @author Mars * */ public class One2many { /** * @param args */ public static void main(String[] args) { //Department dept = add(); Department dept = add2(); queryDepart(dept.getId()); } /** * 一对多查询方法 * @param empId * @return */ static Department queryDepart(int deptId){ Session s = null; Transaction tx =null; try { s=HibernateUtil.getSession(); tx=s.beginTransaction(); Department depart = (Department)s.get(Department.class, deptId); // 分两步:1,根据departid查询部门的相关数据 // 2.根据departid查询相应的employee相关数据 // System.out.println("emp size:"+depart.getEmps().size()); /** * 为了显示更直观下,我没覆盖Employee类的toString() */ System.out.println("emp:"+depart.getEmps()); //涉及懒加载先这么写吧 Hibernate.initialize(depart.getEmps()); tx.commit(); return depart; } finally{ if(s!=null){ s.close(); } } } /** * 一对多添加方法 * 告诉用户所从属的部门 * @return */ static Department add(){ Session s = null; Transaction tx =null; try { Department depart = new Department(); depart.setName("depart name"); //告诉用户所从属的部门 Employee emp1 = new Employee(); emp1.setDepart(depart);//对象模型,建立两个对象的关联 emp1.setName("emp name1"); Employee emp2 = new Employee(); emp2.setDepart(depart);//对象模型,建立两个对象的关联 emp2.setName("emp name2"); s=HibernateUtil.getSession(); tx=s.beginTransaction(); s.save(depart); s.save(emp1); s.save(emp2); tx.commit(); return depart; } finally{ if(s!=null){ s.close(); } } } /** * 一对多添加方法 * 告诉用户所从属的部门及告诉部门所从属的员工 * @return */ static Department add2(){ Session s = null; Transaction tx =null; try { Department depart = new Department(); depart.setName("depart name"); //告诉用户所从属的部门 Employee emp1 = new Employee(); emp1.setDepart(depart);//对象模型,建立两个对象的关联 emp1.setName("emp name1"); Employee emp2 = new Employee(); emp2.setDepart(depart);//对象模型,建立两个对象的关联 emp2.setName("emp name2"); //告诉部门所从属的员工 List<Employee>emps = new ArrayList<Employee>(); emps.add(emp1); emps.add(emp2); depart.setEmps(emps); s=HibernateUtil.getSession(); tx=s.beginTransaction(); s.save(depart); s.save(emp1); s.save(emp2); tx.commit(); return depart; } finally{ if(s!=null){ s.close(); } } } }
四、Map
实体映射文件:
<map name="emps"> <key column="depart_id"/> <map-key type="string" column="name"/> <one-to-many class="Employee" /> </map>
Map是键值对的形式,key不重复
SQL> desc department;
Name Type Nullable Default Comments
---- ------------- -------- ------- --------
ID NUMBER(10)
NAME VARCHAR2(255)
SQL> desc employee;
Name Type Nullable Default Comments
--------- ------------- -------- ------- --------
ID NUMBER(10)
NAME VARCHAR2(255)
DEPART_ID NUMBER(10)
五、数组array
实体映射文件:
<array name="emps"> <key column="depart_id"/> <list-index column="order_colum"/> 表中有单独的整型列表示list-index <one-to-many class="Employee" /> </array>
SQL> desc department;
Name Type Nullable Default Comments
---- ------------- -------- ------- --------
ID NUMBER(10)
NAME VARCHAR2(255)
SQL> desc employee;
Name Type Nullable Default Comments
----------- ------------- -------- ------- --------
ID NUMBER(10)
NAME VARCHAR2(255)
DEPART_ID NUMBER(10)
ORDER_COLUM NUMBER(10) Y
六、 hibernate中集合的选择:
一般都选择set集合,配置方便,而且不允许重复也符合一般的业务逻辑。
如果就是想使用list集合,不想保证正确顺序记录时用bag标签,想保证记录顺序时list标签
array一般很少用,因为数组的尺寸需要掌控,很容易造成数组越界,不便于管理
七、关于类型的一个小实验
第一步:将domain中的属性Set类型修改为HashSet类型和修改相关的setter和getter方法
public HashSet<Employee> getEmps() {
return emps;
}
第二步:
static Department add2(){ Session s = null; Transaction tx =null; try { Department depart = new Department(); depart.setName("depart name"); //告诉用户所从属的部门 Employee emp1 = new Employee(); emp1.setDepart(depart);//对象模型,建立两个对象的关联 emp1.setName("emp name1"); Employee emp2 = new Employee(); emp2.setDepart(depart);//对象模型,建立两个对象的关联 emp2.setName("emp name2"); /** * set时 */ Set<Employee>emps = new HashSet<Employee>(); emps.add(emp1); emps.add(emp2); depart.setEmps(emps); /* //告诉部门所从属的员工 //list集合时 List<Employee>emps = new ArrayList<Employee>(); emps.add(emp1); emps.add(emp2); depart.setEmps(emps);*/ /** * Map集合时 */ // Map<String,Employee>emps = new HashMap<String,Employee>(); // emps.put(emp1.getName(), emp1); // emps.put(emp2.getName(), emp2); // depart.setEmps(emps); /** * 数组 */ /* Employee[] emps = {emp1,emp2}; depart.setEmps(emps);*/ s=HibernateUtil.getSession(); tx=s.beginTransaction(); s.save(depart); s.save(emp1); s.save(emp2); tx.commit(); //做个试验 HashSet hs =(HashSet)depart.getEmps(); return depart; } finally{ if(s!=null){ s.close(); } } }
HashSet hs =(HashSet)depart.getEmps();
此时报错:
Exception in thread "main" java.lang.ClassCastException: org.hibernate.collection.internal.PersistentSet cannot be cast to java.util.HashSet
at cn.itcast.RelationalMapping.One2many.add2(One2many.java:147)
at cn.itcast.RelationalMapping.One2many.main(One2many.java:26)
分析:Hibernate为了方便对集合懒加载操作,在顶层对所有的jdk中的集合进行了改写,所以只要以保存之后再取出来,hibernate已经对数据类型进行转换
所以domain定义时属性不能定义成具体的类,而是定义成接口(如定义成Set而不是HashSet)。
否则无法再hibernate中运行报类型异常
2013-6-2 15:44:18 org.hibernate.property.BasicPropertyAccessor$BasicSetter set
ERROR: HHH000123: IllegalArgumentException in class: cn.itcast.domain.Department, setter method of property: emps
2013-6-2 15:44:18 org.hibernate.property.BasicPropertyAccessor$BasicSetter set
ERROR: HHH000091: Expected type: java.util.HashSet, actual value: org.hibernate.collection.internal.PersistentSet
Exception in thread "main" org.hibernate.PropertyAccessException: IllegalArgumentException occurred while calling setter of cn.itcast.domain.Department.emps
at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:119)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.setPropertyValues(AbstractEntityTuplizer.java:710)
at org.hibernate.tuple.entity.PojoEntityTuplizer.setPropertyValues(PojoEntityTuplizer.java:371)
at org.hibernate.persister.entity.AbstractEntityPersister.setPropertyValues(AbstractEntityPersister.java:4509)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:275)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:192)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:135)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:206)
at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:55)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:191)
at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:49)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:764)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:756)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:752)
at cn.itcast.RelationalMapping.One2many.add2(One2many.java:142)
at cn.itcast.RelationalMapping.One2many.main(One2many.java:26)
Caused by: java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:65)
... 16 more
因为org.hibernate.collection.internal.PersistentSet 是实现了Set接口的,到但是不是从HashSet中继承过来的
结论:在持久化类中(domain类中),类中属性(成员变量)定义成接口不要定义成具体的类(如定义成Set而不是HashSet)。
剩余相关代码:
package cn.itcast.domain; import java.util.Set; /** * 部门类 * @author Mars * */ public class Department { private int id; private String name; private Set<Employee>emps; // private List<Employee>emps; // private Map<String,Employee>emps; // private Employee []emps; public int getId() { return id; } public Set<Employee> getEmps() { return emps; } public void setEmps(Set<Employee> emps) { this.emps = emps; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
package cn.itcast.domain; /** * 员工类 * * @author Mars * */ public class Employee { private int id; private String name; private Department depart; /** * 为了显示更直观下,我没覆盖Department类的toString() */ public String toString() { // TODO Auto-generated method stub return "id:"+this.getId()+" name:"+this.getName(); } public int getId() { return id; } public Department getDepart() { return depart; } public void setDepart(Department depart) { this.depart = depart; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
相关文章推荐
- 【Hibernate学习笔记】映射值类型集合
- [原创]java WEB学习笔记93:Hibernate学习之路---Hibernate 缓存介绍,缓存级别,使用二级缓存的情况,二级缓存的架构集合缓存,二级缓存的并发策略,实现步骤,集合缓存,查询缓存,时间戳缓存
- IOS开发学习笔记(十一)——ObjectC中集合类型的使用
- Hibernate学习笔记(七)【映射值类型集合】
- 【Hibernate学习笔记-5.2】使用@Temporal修饰日期类型的属性
- Hibernate 集合属性List 的使用----Hibernate 学习笔记总结(一)
- Hibernate 集合属性List 的使用----Hibernate 学习笔记总结(一)
- c语言学习笔记(12)条件编译使用分析
- HTML5+CSS3+JS学习笔记-12-使用JS及函数来制作表格加上3D透视效果
- php——学习笔记,数据类型和小例以及echo使用技巧
- Swift学习笔记4——集合类型
- Objective-C 学习笔记12 文件使用结合NSData
- springmvc学习笔记(12)-springmvc注解开发之包装类型参数绑定
- [置顶] 20151215 Hibernate学习笔记------基本的配置和使用方法
- redis学习笔记7--有序集合类型
- MySQL学习笔记12:数据类型
- 【Hibernate学习笔记-5】@Formula注解的使用
- Effective C# 学习笔记(三十九) 使用Dynamic处理范型参数的运行时类型
- FreeBSD学习笔记12-pureftpd使用详解(1)-安装、配置、实现匿名登录
- Hibernate集合类型的延迟加载学习及总结....