1. 多对一的单向关联
从订单(order)到客户(customer)的单向关联 (多个订单对应一个客户)
JavaBean: Customer
public class Customer{
private Integer id;
private String name;
}
JavaBean: Order
public class Order{
private Integer id;
private String orderNumber;
private Double price;
private Customer customer; // 建立从订单到客户的多对一关联
}
customer.hbm.xml:
<hibernate-mapping>
<class name="cn.itcast.many2one.Customer" table="customers">
<id name="id" type="integer">
<column name="id"></column>
<generator class="increment"></generator>
</id>
<property name="name" type="string" access="property">
<column name="name"></column>
</property>
</class>
</hibernate-mapping>
order.hbm.xml:
<hibernate-mapping>
<!-- class标签建立javabean和表之间的映射 -->
<class name="cn.itcast.many2one.Order" table="orders">
<!-- id映射表中的主键 -->
<id name="id" type="integer">
<column name="id"></column>
<!-- 配置主键的生成策略 -->
<generator class="increment"></generator>
</id>
<!--
property建立javabean中的属性和表中列的对应关系
type="string": string表示的是hibernate的类型,该类型是java类型和sql类型之间的桥梁
java中的类型: String name; sql中的类型: varchar(255);
映射一个sql的varchar类型到java的String类型
-->
<!-- access属性表示对javabean属性的访问策略,默认值是property -->
<property name="orderNumber" type="string" access="property">
<!-- column定义表中的列 -->
<column name="orderNumber"></column>
</property>
<property name="price" type="double">
<column name="price"></column>
</property>
<!—
<many-to-one>: 使用该标签来映射多对一关联
* name: 映射的持久化类中的属性
* class: 映射的持久化类中的属性的类型
cascade="save-update" 级联保存和更新
* 就是将order对象所关联的临时对象Customer变成持久对象
持久对象会保存在session的一级缓存中,就能插入到数据库中
update=”false” 指的是不能用session.update(),session.saveOrUpdate()的方式更新
但是可以用hql语句进行更新
-->
<many-to-one name="customer" class="cn.itcast.many2one.Customer" cascade=”save-update”>
<column name="customer_id" ></column> <!-- column表示多的一方(Role)表中的外键 -->
</many-to-one>
</class>
</hibernate-mapping>
2. 一对多的单向关联从客户(customer)到订单(order)的单向关联 (一个客户对应多个订单)
JavaBean: Customer
public class Customer{
private Integer id;
private String name;
private Set<Order> orders = new HashSet<Order>(0); // 开始长度为0
}
JavaBean: Order
public class Order{
private Integer id;
private String orderNumber;
private Double price;
}
Customer.hbm.xml:
<hibernate-mapping>
<class name="cn.itcast.many2one.Customer" table="customers">
<id name="id" type="integer">
<column name="id"></column>
<generator class="increment"></generator>
</id>
<property name="name" type="string" access="property">
<column name="name"></column>
</property>
<!--
配置set集合
Set: 使用set标签配置客户对应的订单集合
table:订单集合中的订单对应的表,可以不加
cascade=”save-update”: 级联保存和更新,当保存customer对象时,同时要保存customer对象多关联的订单集合orders集合
“delete”: 级联删除,删除客户的同时删除订单
inverse=”true”: 表示多的一端(order端) 为主控方法 ---> 看成”全国人民” 全国人民可以记住国家主席 (多的一端说了算)
一的一端(customer端) 不是主控方法 ---> 看成”国家主席” 国家主席是记不住全国人的
Update的时候才有效!!! 如果不写默认的是两边都维护
-->
<set name=”orders” table=”orders” inverse=”true”>
<key>
<!--对应是orders表的外键,可以理解为orderes集合中的订单对象是通过orders表的外键customer_id查询出来的-->
<column name=”customer_id”/>
</key>
<!-- one-to-many表示一对多, class表示集合中存放的对象是Order对象 -->
<one-to-many class=” cn.itcast.many2one.Order”/>
</set>
</class>
</hibernate-mapping>
Order.hbm.xml:
<hibernate-mapping>
<class name="cn.itcast.many2one.Order" table="orders">
<id name="id" type="integer">
<column name="id"></column>
<generator class="increment"></generator>
</id>
<property name="orderNumber" type="string" access="property">
<column name="orderNumber"></column>
</property>
<property name="price" type="double">
<column name="price"></column>
</property>
</class>
</hibernate-mapping>
3. 一对多的双向关联建立从Customer到Order的一对多的双向关联
* 从一的一端查询关联到多的一端
* 从多的一端查询关联到一的一端
* 双向一对多和双向多对一是两种完全相同的情形
JavaBean: Customer
public class Customer{
private Integer id;
private String name;
private Set<Order> orders = new HashSet<Order>(0); // 开始长度为0
}
JavaBean: Order
public class Order{
private Integer id;
private String orderNumber;
private Double price;
private Customer customer; // 建立从订单到客户的多对一关联
}
Customer.hbm.xml:
<hibernate-mapping>
<class name="cn.itcast.many2one.Customer" table="customers">
<id name="id" type="integer">
<column name="id"></column>
<generator class="increment"></generator>
</id>
<property name="name" type="string" access="property">
<column name="name"></column>
</property>
<!--
配置set集合
name: Customer类的orders属性
table: 对应表的表名
set: 使用set标签配置客户对应的订单集合
table:订单集合中的订单对应的表,可以不加
cascade=”save-update”: 级联保存和更新,当保存customer对象是,同时要保存customer对象所关联的订单集合Orders集合
不要设置成cascade=”all”,因为删除一条,其他被关联的也会被删除掉
inverse:是否放弃维护表关系
lazy:是否是懒加载,如果设置为false,则即使不使用它的子元素也会执行查询,影响效率。
-->
<set name=”orders” table=”orders” cascade=”save-update”>
<key>
<!—对应是orders表的外键,可以理解为orderes集合中的订单对象是通过orders表的外键customer_id查询出来的-->
<column name=”customer_id”/>
</key>
<!-- one-to-many表示一对多, class表示集合中存放的对象是Order对象 -->
<one-to-many class=” cn.itcast.many2one.Order”/>
</set>
</class>
</hibernate-mapping>
Order.hbm.xml:
<hibernate-mapping>
<class name="cn.itcast.many2one.Order" table="orders">
<id name="id" type="integer">
<column name="id"></column>
<generator class="increment"></generator>
</id>
<property name="orderNumber" type="string" access="property">
<column name="orderNumber"></column>
</property>
<property name="price" type="double">
<column name="price"></column>
</property>
<!—
<many-to-one>: 使用该标签来映射多对一关联
* name: 映射的持久化类中的属性
* class: 映射的持久化类中的属性的类型
cascade="save-update" 级联保存和更新
* 就是将order对象所关联的临时对象Customer变成持久对象
持久对象会保存在session的一级缓存中,就能插入到数据库中
-->
<many-to-one name="customer" class="cn.itcast.many2one.Customer" cascade=”save-update”>
<column name="customer_id" ></column>
</many-to-one>
</class>
</hibernate-mapping>
public void testDoubleRaletion(){
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
Order orders1=new Order();
orders1.setOrderNumber("001");
orders1.setPrice(20);
Customer c=new Customer();
c.setName("杨逍");
//建立订单和客户的双向关联
//订单和客户关联
orders1.setCustomer(c);
//客户和订单关联
//c.getOrders().add(orders1);
session.save(c);
session.save(orders1);
tx.commit();
session.close();
}
4. 1个javabean映射2张表
一个人在网上有多张相片
对于子表中除了外键,只有一列数据, 可以建立一个JavaBean映射两个表
表的数量一般情况下和javabean的数量保持一致,但这不是绝对的,就比如我们这个例子
建表语句:
CREATE table persons(
pid INT,
name varchar(20)
);
CREATE table imgs(
imgid INT,
img varchar(20)
);
alter table persons
add CONSTRAINT persons_pk primary key (pid);
alter table imgs
add constraint imgs_fk foreign key imgs(imgid) references persons(pid);
JavaBean:
public class Person {
private Integer id;
private String name;
private Set<String> imgs = new HashSet<String>(); // 将另一个表映射成自己的一个集合
... get和set方法
}
Person.hbm.xml
<?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="cn.itcast.domain2">
<class name="Person" table="persons">
<id name="id" type="integer">
<column name="pid"></column>
<generator class="increment"></generator>
</id>
<property name="name" column="name" type="string"/>
<!-- 以下通过一个Set元素映射Person类中的set集合
name是指:Person类中的成员变量名,用set映射,说明它是一个Set类型的对象
table:是指Person类中的成员变量imgs的数据来自于imgs表
-->
<set name="imgs" table="imgs">
<!-- 只要指定了另一个表,必须要指定另一个表中的外銉是哪一个字段 -->
<key column="imgid"></key>
<!-- 因为另一个表中,即imgs表中,除了外键之外只有一个字段,所以可以使用element元素影射
element的column属性是指items.imgs属性的值都来自于imgs表的img字段.
-->
<element column="imgname" type="string"></element>
</set>
</class>
</hibernate-mapping>
拓展: 查询没有图片的人
方法1:
select pid,pname,imgname // 查询两张表
from persons p left join imgs i on p.pid=i.imgid
where i.imgname is null;
方法2:
SELECT *
FROM persons
<span style="font-family:Comic Sans MS;">WHERE NOT EXISTS (SELECT * FROM imgs WHERE persons.pid=imgs.imgid);
</span>
5. bag和set的区别Set: new HashSet() - 无序, 不能重复。
Bag: new ArrayList() 用bag来映射的List是无序的集合, 可以重复
new LinkedArrayList()
配置文件书写略有不同:
<set name="emps" table="emp" cascade="save-update" inverse="false" lazy="true">
<key column="edept"></key>
<one-to-many class="Emp"/>
</set>
<bag name="cars" cascade="save-update" inverse="false">
<key column="c_pid"/>
<one-to-many class="Car"/>
</bag>