客户和订单关系:客户是一的一方,订单是多的一方。
customer表:
CREATE TABLE `customer` (
`ID` int(4) NOT NULL AUTO_INCREMENT ,
`CNAME` char(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`BANK` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`PHONE` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
PRIMARY KEY (`ID`)
)
orders表:
CUSTOMER_ID是外键!
CREATE TABLE `orders` (
`ID` int(4) NOT NULL AUTO_INCREMENT ,
`ORDERNO` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,
`MONEY` double(10,2) NULL DEFAULT NULL ,
`CUSTOMER_ID` int(4) NULL DEFAULT NULL ,
PRIMARY KEY (`ID`),
FOREIGN KEY (`CUSTOMER_ID`) REFERENCES `customer` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE,
INDEX `CUSTOMER_ID` (`CUSTOMER_ID`) USING BTREE
)
PO对象
Customer.java
package com.PO;
import java.util.HashSet;
import java.util.Set;
/**
* Company entity. @author tuke
*/
public class Customer implements java.io.Serializable {
private Integer id;
private String cname; //客户名称
private String bank; //银行账号
private String phone; //电话号码
private Set<Orders> orderses = new HashSet<Orders>(); //关联另外一个类
// Constructors
/** default constructor */
public Customer() {
}
/** full constructor */
public Customer(String cname, String bank, String phone, Set<Orders> orderses) {
this.cname = cname;
this.bank = bank;
this.phone = phone;
this.orderses = orderses;
}
// Property accessors
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCname() {
return this.cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public String getBank() {
return this.bank;
}
public void setBank(String bank) {
this.bank = bank;
}
public String getPhone() {
return this.phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Set<Orders> getOrderses() {
return this.orderses;
}
public void setOrderses(Set<Orders> orderses) {
this.orderses = orderses;
}
}
Customer.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.PO.Customer" table="customer" catalog="onetomany">
<id name="id" type="integer">
<column name="ID" />
<generator class="identity"></generator>
</id>
<property name="cname" column="CNAME" type="string"></property>
<property name="bank" column="BANK" type="string"> </property>
<property name="phone" column="PHONE" type="string"> </property>
<!-- 一对多双向映射customer到orders,单的一方配置 ,name是PO类Company的属性,table是关联表名,如果设置成inverse为true,以设定一方到多方的设定是逆向映射,即可以从多放引导到一方。一定要加lazy="false"否则会出现延迟加载错误-->
<set name="orderses" table="orders" inverse="true" lazy="false" cascade="all" >
<key column="CUSTOMER_ID"/><!--外键字段: <key>标签指定的外键字段必须和<many-to-one>指定的外键字段一致 -->
<one-to-many class="com.PO.Orders" /><!-- 用关联表对应的PO类实例做value值 -->
</set>
</class>
</hibernate-mapping>
Orders.java
package com.PO;
/**
* Orders entity. @author tuke
*/
public class Orders implements java.io.Serializable {
private Integer id;
private String orderno;
private double money;
private Customer customer;//关联customer
/** default constructor */
public Orders() {
}
/** full constructor */
public Orders(Customer customer, String orderno, double money) {
this.customer = customer;
this.orderno = orderno;
this.money = money;
}
// Property accessors
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public Customer getCompany() {
return this.customer;
}
public void setCompany(Customer customer) {
this.customer = customer;
}
public String getOrderno() {
return this.orderno;
}
public void setOrderno(String orderno) {
this.orderno = orderno;
}
public double getMoney() {
return this.money;
}
public void setMoney(double money) {
this.money = money;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
Orders.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="com.PO.Orders" table="orders" catalog="onetomany">
<id name="id" type="integer">
<column name="ID" />
<generator class="identity"></generator>
</id>
<property name="orderno" column="ORDERNO" type="string"> </property>
<property name="money" column="MONEY" type="double"> </property>
<!-- 一对多双向关联映射中,多的一方配置manytoone ,name是PO属性,一定要加lazy="false"否则会出现延迟加载错误-->
<many-to-one name="customer" column="CUSTOMER_ID" class="com.PO.Customer" lazy="false">
</many-to-one>
</class>
</hibernate-mapping>
TestBean.java
package com.test;
import java.util.Random;
import com.PO.Customer;
import com.PO.Orders;
import com.dao.OneManyDao;
public class TestBean {
OneManyDao dao=new OneManyDao();
Random rnd=new Random();
public void addCustomer(){
Customer customer=new Customer();
customer.setCname("tuke");
customer.setBank("中国银行");
customer.setPhone("027-12121221");
//数据库操作
dao.addCustomer(customer);
}
public Customer loadCustomer(Integer id){
return dao.loadCustomer(id);
}
//为客户customer添加订单orders,被控方操作
public void addOrders(Customer customer){
//随机生成order对象
Orders order=new Orders();
order.setOrderno(new Integer(rnd.nextInt()*10000).toString());
order.setMoney(new Double(rnd.nextDouble()*10000));
order.setCustomer(customer);//如果映射文件正确,则orders表的CUSTOMER_ID字段会有customer的ID
//把生成的order对象,加入customer的set集合中
customer.getOrderses().add(order);
System.out.println( customer.getOrderses().contains(order));
dao.addOrders(order);
}
public Orders loadOrders(Integer id){
return dao.loadOrders(id);
}
}
OneManyDao.java
package com.dao;
import org.hibernate.Session;
import org.hibernate.Transaction;
import SessionFactory.HibernateSessionFactory;
import com.PO.Customer;
import com.PO.Orders;
/**
* Data access object (DAO) for domain model
* @author tuke
*/
public class OneManyDao {
//添加客户信息
public void addCustomer(Customer customer){
Session session=HibernateSessionFactory.getSession();
Transaction ts=null;
try{
ts=session.beginTransaction();
//保存customer对象的同时,会保存其包含的所有订单
session.saveOrUpdate(customer);
ts.commit();
}catch(Exception ex){
ts.rollback();
System.out.println("添加客户失败!");
}finally{
HibernateSessionFactory.closeSession();
}
}
//加载客户信息
public Customer loadCustomer(Integer id){
Session session=HibernateSessionFactory.getSession();
Transaction ts=null;
Customer customer=null;
try{
ts=session.beginTransaction();
//加载customer信息时,同样会加载其所有的订单信息
customer=(Customer)session.get(Customer.class, id);
ts.commit();
}catch(Exception ex){
ts.rollback();
System.out.println("获取客户失败!");
}finally{
HibernateSessionFactory.closeSession();
}
return customer;
}
//添加订单信息
public void addOrders(Orders order){
Session session=HibernateSessionFactory.getSession();
Transaction ts=null;
try{
ts=session.beginTransaction();
session.save(order);
ts.commit();
}catch(Exception ex){
ts.rollback();
System.out.println("添加订单失败!");
}finally{
HibernateSessionFactory.closeSession();
}
}
//加载订单信息
public Orders loadOrders(Integer id){
Session session=HibernateSessionFactory.getSession();
Transaction ts=null;
Orders order=null;
try{
ts=session.beginTransaction();
order=(Orders)session.get(Orders.class, id);
ts.commit();
}catch(Exception ex){
ts.rollback();
System.out.println("获取订单失败!");
}finally{
HibernateSessionFactory.closeSession();
}
return order;
}
}
测试页面test.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page import="com.PO.*" import="com.test.*" import="java.text.NumberFormat"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>hibernate的一对多双向关联关系映射</title>
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<h2>hibernate的一对多双向关联关系映射</h2>
<hr>
<jsp:useBean id="test" class="com.test.TestBean"></jsp:useBean>
<%
test.addCustomer();
Integer id=new Integer(1);
Customer customer=test.loadCustomer(id);
//给该客户增加三个订单
test.addOrders(customer);
test.addOrders(customer);
test.addOrders(customer);
//根据指定的客户,得到该客户的所有订单
NumberFormat nf=NumberFormat.getCurrencyInstance();
out.println("<br>客户"+customer.getCname()+"的所有订单");
Iterator<Orders> it=customer.getOrderses().iterator();
Orders order=null;
while(it.hasNext()){
order=(Orders)it.next();
System.out.println(order.getOrderno());
out.println("<br>订单号:"+order.getOrderno());
out.println("<br>订单金额:"+nf.format(order.getMoney()));
}
//根据指定的订单,得到其所属的客户
order=test.loadOrders(new Integer(28));
customer=order.getCustomer();
out.println("<br>");
out.println("<br>订单号为:"+order.getOrderno().trim()+"的所属客户为:"+customer.getCname());
%>
</body>
</html>
测试结果:
控制台打印的sql语句是:
Hibernate:
insert
into
onetomany.customer
(CNAME, BANK, PHONE)
values
(?, ?, ?)
Hibernate:
select
customer0_.ID as ID1_0_,
customer0_.CNAME as CNAME1_0_,
customer0_.BANK as BANK1_0_,
customer0_.PHONE as PHONE1_0_
from
onetomany.customer customer0_
where
customer0_.ID=? //上面是save和load一个customer
Hibernate:
select
orderses0_.CUSTOMER_ID as CUSTOMER4_1_,
orderses0_.ID as ID1_,
orderses0_.ID as ID0_0_,
orderses0_.ORDERNO as ORDERNO0_0_,
orderses0_.MONEY as MONEY0_0_,
orderses0_.CUSTOMER_ID as CUSTOMER4_0_0_
from
onetomany.orders orderses0_
where
orderses0_.CUSTOMER_ID=?
true
Hibernate:
insert
into
onetomany.orders
(ORDERNO, MONEY, CUSTOMER_ID)
values
(?, ?, ?)
true
Hibernate:
insert
into
onetomany.orders
(ORDERNO, MONEY, CUSTOMER_ID)
values
(?, ?, ?)
true
Hibernate:
insert
into
onetomany.orders
(ORDERNO, MONEY, CUSTOMER_ID)
values
(?, ?, ?) //上面是给客户添加三个订单的sql
741563392
-1674530192
-635127520 //这是三个customer实例中set集合里的三个订单号
Hibernate:
select
orders0_.ID as ID0_0_,
orders0_.ORDERNO as ORDERNO0_0_,
orders0_.MONEY as MONEY0_0_,
orders0_.CUSTOMER_ID as CUSTOMER4_0_0_
from
onetomany.orders orders0_
where
orders0_.ID=?
Hibernate:
select
customer0_.ID as ID1_0_,
customer0_.CNAME as CNAME1_0_,
customer0_.BANK as BANK1_0_,
customer0_.PHONE as PHONE1_0_
from
onetomany.customer customer0_
where
customer0_.ID=?
Hibernate:
select
orderses0_.CUSTOMER_ID as CUSTOMER4_1_,
orderses0_.ID as ID1_,
orderses0_.ID as ID0_0_,
orderses0_.ORDERNO as ORDERNO0_0_,
orderses0_.MONEY as MONEY0_0_,
orderses0_.CUSTOMER_ID as CUSTOMER4_0_0_
from
onetomany.orders orderses0_
where
orderses0_.CUSTOMER_ID=?
总结:
一对多双向关联映射:
* 在“一”一端的集合上使用<key>,<key>标签指定的是外键字段,在对方表中加入一个外键指向一一端
* 在多一端采用<many-to-one>
注意:<key>标签指定的外键字段必须和<many-to-one>指定的外键字段一致,否则引用字段的错误
关键配置代码如下:
<!-- 一对多双向映射customer到orders,单的一方配置 ,name是PO类Company的属性,table是关联表名,如果设置成inverse为true,以设定一方到多方的设定是逆向映射,即可以从多放引导到一方。一定要加lazy="false"否则会出现延迟加载错误-->
<set name="orderses" table="orders" inverse="true" lazy="false" cascade="all" >
<key column="CUSTOMER_ID"/><!--外键字段: <key>标签指定的外键字段必须和<many-to-one>指定的外键字段一致 -->
<one-to-many class="com.PO.Orders" /><!-- 用关联表对应的PO类实例做value值 -->
</set>
<!-- 一对多双向关联映射中,多的一方配置manytoone ,name是PO属性,一定要加lazy="false"否则会出现延迟加载错误-->
<many-to-one name="customer" column="CUSTOMER_ID" class="com.PO.Customer" lazy="false">
</many-to-one>