Hibernate映射

数据库表中存在的关系在hibernate为各实体之间的关系。

实体之间有三种关系:

  一对多:一个用户,生成多个订单,每一个订单只能属于一个用户

    建表原则:在多的一方创建一个字段,作为外键,指向一的一方的主键.

  多对多:一个学生可以选择多门课程,一个课程可以被多个学生选择.

    建表原则:创建第三张表,中间表至少有两个字段,分别作为外键指向多对多双方主键.

  一对一(特殊.最少):一个公司只能有一个注册地址,一个注册地址,只能被一个公司使用.(否则将两个表建到一个表.)

   建表原则:

    唯一外键:一对一的双方,假设一方是多的关系.需要在多的一方创建一个字段,作为外键.指向一的一方的主键.但是在外键添加一个unique.

    主键对应: 一对一的双方,通过主键进行关联.

Hibernate中一对多的配置:

第一步:创建两个实体:

客户实体:

 1 public class Customer {
 2     private Integer cid;
 3     private String cname;
 4     // 一个客户有多个订单.
 5     private Set<Order> orders = new HashSet<Order>();
 6     public Integer getCid() {
 7         return cid;
 8     }
 9     public void setCid(Integer cid) {
10         this.cid = cid;
11     }
12     public String getCname() {
13         return cname;
14     }
15     public void setCname(String cname) {
16         this.cname = cname;
17     }
18     public Set<Order> getOrders() {
19         return orders;
20     }
21     public void setOrders(Set<Order> orders) {
22         this.orders = orders;
23     }
24     
25 }

订单实体:

 1 public class Order {
 2     private Integer oid;
 3     private String addr;
 4     // 订单属于某一个客户.放置一个客户的对象.
 5     private Customer customer;
 6     public Integer getOid() {
 7         return oid;
 8     }
 9     public void setOid(Integer oid) {
10         this.oid = oid;
11     }
12     public String getAddr() {
13         return addr;
14     }
15     public void setAddr(String addr) {
16         this.addr = addr;
17     }
18     public Customer getCustomer() {
19         return customer;
20     }
21     public void setCustomer(Customer customer) {
22         this.customer = customer;
23     }
24     
25 }

第二步:建立映射:

Customer.hbm.xml

 1 <hibernate-mapping>
 2     <class name="cn.itcast.hibernate3.demo2.Customer" table="customer">
 3         <!-- 配置唯一标识 -->
 4         <id name="cid" column="cid">
 5             <generator class="native"/>
 6         </id>
 7         <!-- 配置普通属性 -->
 8         <property name="cname" column="cname" length="20"/>
 9         
10         <!-- 建立映射 -->
11         <!-- 配置一个集合 <set>的name Customer对象中的关联对象的属性名称. -->
12         <set name="orders">
13             <!-- <key>标签中column:用来描述一对多多的一方的外键的名称. -->
14             <key column="cno"></key>
15             <!-- 配置一个<one-to-many>标签中class属性:订单的类的全路径 -->
16             <one-to-many class="cn.itcast.hibernate3.demo2.Order"/>
17         </set>
18     </class>
19 </hibernate-mapping>

Order.hbm.xml

 1 <hibernate-mapping>
 2     <class name="cn.itcast.hibernate3.demo2.Order" table="orders">
 3         <!-- 配置唯一标识  -->
 4         <id name="oid" column="oid">
 5             <generator class="native"/>
 6         </id>
 7         <!-- 配置普通属性 -->
 8         <property name="addr" column="addr" length="50"/>
 9         <!-- 配置映射 -->
10         <!-- 
11         <many-to-one>标签
12             name     :关联对象的属性的名称.
13             column    :表中的外键名称.
14             class    :关联对象类的全路径
15         -->
16         <many-to-one name="customer" column="cno" class="cn.itcast.hibernate3.demo2.Customer"/>
17     </class>
18 </hibernate-mapping>

第三步:将映射放到核心配置文件中,完成。

测试:

 1 @Test
 2 // 向客户表插入一个客户,在订单表中插入两个订单.
 3 public void demo1(){
 4     Session session = HibernateUtils.openSession();
 5     Transaction tx = session.beginTransaction();
 6     
 7     // 定义一个客户:
 8     Customer customer = new Customer();
 9     customer.setCname("老汤姆");
10     
11     // 定义两个订单:
12     Order order1 = new Order();
13     order1.setAddr("吉尼斯");
14     
15     Order order2 = new Order();
16     order2.setAddr("西西里");
17     
18     // 建立关系:
19     order1.setCustomer(customer);
20     order2.setCustomer(customer);
21     
22     customer.getOrders().add(order1);
23     customer.getOrders().add(order2);
24     
25     session.save(customer);
26     session.save(order1);
27     session.save(order2);
28     
29     tx.commit();
30     session.close();

~成功

但是,这样保存数据太麻烦,在hibernate中存在级联保存:操作当前对象的时候,关联的对象也会被保存

只需在Customer.hbm.xml中set中加入<set name="orders" cascade="save-update">

 1 @Test
 2 // 保存客户级联订单.
 3 // <set>集合是客户的关联订单对象的集合.所以在<set>上配置一个属性:cascade="save-update"
 4 public void demo3(){
 5     Session session = HibernateUtils.openSession();
 6     Transaction tx = session.beginTransaction();
 7     
 8     // 定义客户:
 9     Customer customer = new Customer();
10     customer.setCname("老汤姆");
11     
12     // 定义订单:
13     Order order = new Order();
14     order.setAddr("吉尼斯");
15     order.setCustomer(customer);
16     
17     customer.getOrders().add(order);
18     
19     // 保存的时候只保存一方:
20     session.save(customer);
21     
22     tx.commit();
23     session.close();
24 }

当然,hibernate中不止一种级联

none			:不使用级联
dave-update		:保存或更新的时候级联
delete			:删除的时候级联
all			:除了孤儿删除以外的所有级联.
delete-orphan	        :孤儿删除(孤子删除).
* 仅限于一对多.只有一对多时候,才有父子存在.认为一的一方是父亲,多的一方是子方.
* 当一个客户与某个订单解除了关系.将外键置为null.订单没有了所属客户,相当于一个孩子没有了父亲.将这种记录就删除了.
all-delete-orphan	:包含了孤儿删除的所有的级联.

另外,hibernate中多表之间由于外键存在双向维护,导致产生多余的sql语句,同样在Customer.hbm.xml中<set name="orders" cascade="save-update" inverse="true">

当inverse=true时,就是告诉Customer放弃对外键的维护权。

Hibernate中多对多的配置和一对多差不多,只是在各自的实体类中都存在对方的实体类集合,另外xml中如下:

Course.hbm.xml

 1 <hibernate-mapping>
 2     <class name="cn.itcast.hibernate3.demo3.Course" table="course">
 3         <!-- 配置唯一标识 -->
 4         <id name="cid" column="cid">
 5             <generator class="native"/>
 6         </id>
 7         <!-- 配置普通属性 -->
 8         <property name="cname" column="cname" length="20"/>
 9         <!-- 配置与学生关联映射 -->
10         <!-- <set>中name:对应当前类中的学生的集合的名称  table:中间表的名称-->
11         <set name="students" table="stu_cour" inverse="true">
12             <!-- <key>中column:当前类在中间表中外键 -->
13             <key column="cno"></key>
14             <!-- <many-to-many>中class:另一方的类全路径. column:另一方在中间表中外键名称 -->
15             <many-to-many class="cn.itcast.hibernate3.demo3.Student" column="sno"/>
16         </set>
17     </class>
18 </hibernate-mapping>

Student.hbm.xml

 1 <hibernate-mapping>
 2     <class name="cn.itcast.hibernate3.demo3.Student" table="student">
 3         <!-- 配置唯一标识 -->
 4         <id name="sid" column="sid">
 5             <generator class="native"/>
 6         </id>
 7         <!-- 配置普通属性 -->
 8         <property name="sname" column="sname" length="20"/>
 9         
10         <!-- 配置关联映射 -->
11         <!-- <set>标签 name:对应学生中的课程集合的名称   table:中间表名称. -->
12         <set name="courses" table="stu_cour" cascade="save-update,delete">
13             <!-- <key>中column写 当前类在中间表的外键.-->
14             <key column="sno"></key>
15             <!-- <many-to-many>中class:另一方类的全路径. column:另一方在中间表中外键名称-->
16             <many-to-many class="cn.itcast.hibernate3.demo3.Course" column="cno"/>
17         </set>
18     </class>
19 </hibernate-mapping>

另外,对应多对多中数据的删除,建议采用remove来删除数据

 1 @Test
 2 // 多对多的学生退选.
 3 public void demo4(){
 4     Session session = HibernateUtils.openSession();
 5     Transaction tx = session.beginTransaction();
 6     
 7     // 查询一号学生
 8     Student student = (Student) session.get(Student.class, 1);
 9     Course course = (Course) session.get(Course.class, 2);
10     student.getCourses().remove(course);
11     
12     tx.commit();
13     session.close();
14 }