Hibernate映射List,其中List中的元素可以是String、Long、Date等可以直接映射到字段上的java类型,较为复杂的就是List中的元素的类型为我们自定义的类型。
以Team类为例:
(1)映射的List中的元素为我们自定义的Student类型:
持久化类Team:
- package bean;
- import java.util.List;
- public class Team {
- private long id;
- private String name;
- private List<Student> students;
- //省略setXxx()、getXxx()方法
- }
- package bean;
- public class Student {
- private long id;
- private long cardID;
- private String name;
- private int age;
- private Team team;
- //省略setXxx()、getXxx()方法
- }
- <hibernate-mapping>
- <class name="bean.Team" table="team">
- <id name="id" column="id" type="long">
- <generator class="increment"></generator>
- </id>
- <property name="name" column="name" type="string"></property>
- <list name="students" cascade="all">
- <key column="team_id"></key>
- <index column="index_"></index><!-- 注意index是数据库中的关键字要避免与其冲突,此处index_对应元素在List中的索引 -->
- <one-to-many class="bean.Student"/>
- </list>
- </class>
- </hibernate-mapping>
- <hibernate-mapping>
- <class name="bean.Student" table="students">
- <id name="id" column="id" type="long">
- <generator class="increment"></generator>
- </id>
- <property name="name" column="name" type="string"></property>
- <property name="age" column="age" type="int"></property>
- <property name="cardID" column="cardID" type="long"></property>
- <many-to-one name="team" class="bean.Team" column="team_id" cascade="none"></many-to-one>
- </class>
- </hibernate-mapping>
(1)Team和Student为双向关联关系,特别需要注意延迟加载lazy属性、cascade级联属性、inverse等属性的设置。
(2)<list>中的<index>子元素指定元素在List中的索引字段,不必在Student类中加入这一属性。students表中的team_id字段参照team表中的id字段,两表的结构如下:
级联保存Team对象:
- tx=session.beginTransaction();
- Team t1=new Team();
- t1.setName("team1");
- t1.setStudents(new ArrayList<Student>());
- t1.getStudents().add(new Student(1001L,23,"zhangsan"));
- t1.getStudents().add(new Student(1002L,23,"lisi"));
- t1.getStudents().add(new Student(1003L,23,"wangwu"));
- session.save(t1);
- tx.commit();
- Hibernate: select max(id) from team
- Hibernate: select max(id) from students
- Hibernate: insert into team (name, id) values (?, ?)
- Hibernate: insert into students (name, age, cardID, team_id, id) values (?, ?, ?, ?, ?)
- Hibernate: insert into students (name, age, cardID, team_id, id) values (?, ?, ?, ?, ?)
- Hibernate: insert into students (name, age, cardID, team_id, id) values (?, ?, ?, ?, ?)
- Hibernate: update students set team_id=?, index_=? where id=?//可以看出Hibernate先保存对象属性的默认值,然后再更新对象
- Hibernate: update students set team_id=?, index_=? where id=?
- Hibernate: update students set team_id=?, index_=? where id=?
删除对象:
- Team t=(Team)session.get(Team.class,2L);
- session.delete(t);
若将cascade设为save-update即不具有级联删除的级联级别,控制台输出SQL语句如下:
- Hibernate: select team0_.id as id0_0_, team0_.name as name0_0_ from team team0_ where team0_.id=?
- Hibernate: update students set team_id=null, index_=null where team_id=?
- Hibernate: delete from team where id=?
可将cascade改为all或其他值实现级联删除。
(2)至于较为简单的映射List的情况,以List中的元素为String类型为例,修改如下
(1).修改Team的students属性类型为List<String>,并修改其set、get方法;
(2).修改Team.hbm.xml映射文件:
- <list name="students" cascade="save-update" table="students">
- <key column="team_id"></key>
- <index column="index_"></index><!-- 注意index是数据库中的关键字 -->
- <!-- <one-to-many class="bean.Student"/> -->
- <element column="name" type="string"></element>
- </list>
(1)<element>对应于List中的元素,即学生的姓名。
(2)students表的主键为(team_id,index_)组合主键(这与映射Map<Long,String>中表的结构很相似)。两表结构如下:
保存Team对象:
- tx=session.beginTransaction();
- Team t1=new Team();
- t1.setName("team1");
- t1.setStudents(new ArrayList<String>());
- t1.getStudents().add("zhangsan");
- t1.getStudents().add("lisi");
- t1.getStudents().add("wangwu");
- session.save(t1);
在保存时遇到了一个异常:Caused by: java.sql.SQLException: Field 'id' doesn't have a default value,解决办法:注释掉hibernate.cfg.xml文件中的Student映射:
- <!-- <mapping resource="Student.hbm.xml"/> --> ,因为与原先的students表的结构不同(原表中有id主键),所以需删除原students表。
删除Team对象:
若将cascade设为save-update(即没有级联删除的级别)则依然会将students表中的对应记录删除,而不是将某些字段设为NULL。(与映射Set<String>相似)