hibernate中的多对一配置有两种情况:
一种是子表的外键对应主表的主键id。
另一种是子表的外键对应主表的非主键字段,一般是一个唯一的字段。(常见的场景是订单主表跟订单产品明细表,主表跟子表都是用id作为主键,但是两者之间通过orderNo(订单号)来关联)
下面根据这两种情况,简单介绍一下hibernate映射文件的配置。
第一种情况,假设主表是部门表(department),字表是员工表(employee)。
domain类如下:
package com.xigua.domain;
public class Department {
/**
* 主键id
*/
private Long id;
/**
* 部门名称
*/
private String departName;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getDepartName() {
return departName;
}
public void setDepartName(String departName) {
this.departName = departName;
}
}
package com.xigua.domain;
/**
* 员工
* @author Administrator
*
*/
public class Employee {
/**
* 主键id
*/
private Long id;
/**
* 员工名称
*/
private String empName;
/**
* 部门对象
*/
private Department department;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
}
对应的hibernate映射文件如下:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "D:\tools\hibernate\dtd\hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.xigua.domain"> <class name="Department"> <id name="id"> <generator class="native" /> </id> <property name="departName" column="depart_name" /> <!-- 这个是一对多的配置,暂时不需要 <set name="emps"> <key column="depart_id"></key> <one-to-many class="Employee" /> </set> --> </class> </hibernate-mapping>
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "D:\tools\hibernate\dtd\hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.xigua.domain"> <class name="Employee"> <id name="id"> <generator class="native"/> </id> <property name="empName" column="emp_name"/> <!-- 这里是多对一配置,设置name跟 column属性即可,其余的属性配置都不是必须的 --> <many-to-one name="department" column="depart_id"/> </class> </hibernate-mapping>
经过上述的配置之后,就将Employee跟Department进行了多对一绑定了。
可敲下面的代码验证:
package com.xigua.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.xigua.domain.Department;
import com.xigua.domain.Employee;
import com.xigua.utils.HibernateUtil;
public class Test1 {
public static void main(String args[]) {
save();
query();
}
public static void save() {
Session session = null;
Transaction tx = null;
try{
session = HibernateUtil.getSession();
tx = session.beginTransaction();
Department depart = new Department();
depart.setDepartName("dev");
Employee emp1 = new Employee();
emp1.setEmpName("xigua1");
// 级联保存员工的部门
emp1.setDepartment(depart);
session.save(depart);
session.save(emp1);
tx.commit();
}catch(Exception e) {
if(tx != null) {
tx.rollback();
}
throw e;
}finally {
if(session != null) {
session.close();
}
}
}
public static void query() {
Session session = null;
try{
session = HibernateUtil.getSession();
Employee emp = (Employee) session.get(Employee.class, 1L);
System.out.println(emp.getEmpName());
// 级联查看员工对应的部门
Department depart = emp.getDepartment();
System.out.println(depart.getDepartName());
}catch(Exception e) {
throw e;
}finally {
if(session != null) {
session.close();
}
}
}
}
如果想在Department对象中也绑定一对多关系,则需要修改Department.java类跟对应的hibernate映射文件。
Department.java类中添加一个Set<Employee>集合对象,对应的hibernate文件中也配置一个<Set>标签,具体见下面的代码。
添加Set<Employee>集合对象后的Department.java类:
package com.xigua.domain;
import java.util.Set;
public class Department {
/**
* 主键id
*/
private Long id;
/**
* 部门名称
*/
private String departName;
/**
* set集合 存在该部门下的员工信息
*/
public Set<Employee> emps;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getDepartName() {
return departName;
}
public void setDepartName(String departName) {
this.departName = departName;
}
public Set<Employee> getEmps() {
return emps;
}
public void setEmps(Set<Employee> emps) {
this.emps = emps;
}
}
对应的hibernate映射文件也添加<Set>标签:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "D:\tools\hibernate\dtd\hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.xigua.domain"> <class name="Department"> <id name="id"> <generator class="native" /> </id> <property name="departName" column="depart_name" /> <!-- 这个是一对多的配置--> <set name="emps"> <key column="depart_id"></key> <one-to-many class="Employee" /> </set> </class> </hibernate-mapping>
以上就配置好了部门对象到员工对象的一对多关系。
可敲下面的代码进行验证:
package com.xigua.test;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.xigua.domain.Department;
import com.xigua.domain.Employee;
import com.xigua.utils.HibernateUtil;
public class Test2 {
public static void main(String args[]) {
save();
query();
}
public static void save() {
Session session = null;
Transaction tx = null;
try{
session = HibernateUtil.getSession();
tx = session.beginTransaction();
Employee emp1 = new Employee();
emp1.setEmpName("xigua1");
Employee emp2 = new Employee();
emp2.setEmpName("xigua2");
Department depart = new Department();
depart.setDepartName("dev");
// 级联保存employee对象
Set<Employee> emps = new HashSet<Employee>();
emps.add(emp1);
emps.add(emp2);
depart.setEmps(emps);
session.save(emp1);
session.save(emp2);
session.save(depart);
tx.commit();
}catch(Exception e) {
if(tx != null) {
tx.rollback();
}
throw e;
} finally {
if(session != null) {
session.close();
}
}
}
public static void query() {
Session session = null;
try{
session = HibernateUtil.getSession();
Department depart = (Department) session.get(Department.class, 1L);
System.out.println(depart.getDepartName());
// 级联获取部门员工数据
Set<Employee> emps = depart.getEmps();
if(emps != null && emps.size() > 0) {
for(Employee emp : emps) {
System.out.println(emp.getEmpName());
}
}
} catch (Exception e) {
throw e;
} finally {
if(session != null) {
session.close();
}
}
}
}
下面要说的是第二种多对一关系,即字表的外面不是主表的主键id的情况,这里我用订单主表跟订单产品明细表来举例。
先建好OrderMaster.java对象跟OrderDetail.java对象,通过orderNo(订单号)来关联。
package com.xigua.domain;
import java.util.Set;
public class OrderMaster {
/**
* 订单主表主键id
*/
private Long id;
/**
* 订单号
*/
private String orderNo;
/**
* 一对多关系, 订单主表记录关联多个订单明细记录
*/
private Set<OrderDetail> orderDetails;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public Set<OrderDetail> getOrderDetails() {
return orderDetails;
}
public void setOrderDetails(Set<OrderDetail> orderDetails) {
this.orderDetails = orderDetails;
}
}
package com.xigua.domain;
public class OrderDetail {
/**
* 明细表主键id
*/
private Long id;
// private String orderNo; // 不需要定义了,定义了OrderMaster足够了
/**
* 产品代码
*/
private String productCode;
/**
* 产品数量
*/
private int productQty;
/**
* 多对一关联,订单明细表记录关联的订单主表记录(每条订单明细记录都有对应的订单主表记录)
*/
private OrderMaster orderMaster;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getProductCode() {
return productCode;
}
public void setProductCode(String productCode) {
this.productCode = productCode;
}
public int getProductQty() {
return productQty;
}
public void setProductQty(int productQty) {
this.productQty = productQty;
}
public OrderMaster getOrderMaster() {
return orderMaster;
}
public void setOrderMaster(OrderMaster orderMaster) {
this.orderMaster = orderMaster;
}
}
对应的映射文件如下:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "D:\tools\hibernate\dtd\hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.xigua.domain"> <class name="OrderMaster" table="order_master"> <id name="id"> <generator class="native"/> </id> <property name="orderNo" column="order_no"/> <!-- 一对多配置 --> <set name="orderDetails"> <key column="order_no"></key> <one-to-many class="OrderDetail"/> </set> </class> </hibernate-mapping>
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "D:\tools\hibernate\dtd\hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.xigua.domain"> <class name="OrderDetail" table="order_detail"> <id name="id"> <generator class="native"/> </id> <!-- 配置了多对一关系,明细对象中这个orderNo就不需要配置了, OrderDetail.java类中也不需要定义orderNo的属性字段了 <property name="orderNo" column="order_no"/> --> <property name="productCode" column="product_code"/> <property name="productQty" column="product_qty"/> <!-- 这里的多对一关联,由于字表的外键不是对应主表的主键id,而是orderNo属性,所以要添加property-ref="orderNo"的配置 这个orderNo指的是OrderMaster映射文件中的orderNo property --> <many-to-one name="orderMaster" column="order_no" property-ref="orderNo"/> </class> </hibernate-mapping>
测试类代码如下:
package com.xigua.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.xigua.domain.OrderDetail;
import com.xigua.domain.OrderMaster;
import com.xigua.utils.HibernateUtil;
public class Test3 {
public static void main(String args[]) {
save();
query();
}
public static void save() {
Session session = null;
Transaction tx = null;
try{
session = HibernateUtil.getSession();
tx = session.beginTransaction();
OrderMaster orderMaster = new OrderMaster();
orderMaster.setOrderNo("201408100000001");
OrderDetail orderDetail1 = new OrderDetail();
orderDetail1.setProductCode("18013-02");
orderDetail1.setProductQty(10);
// 级联保存orderMaster
orderDetail1.setOrderMaster(orderMaster);
OrderDetail orderDetail2 = new OrderDetail();
orderDetail2.setProductCode("18018-01");
orderDetail2.setProductQty(5);
// 级联保存orderMaster
orderDetail2.setOrderMaster(orderMaster);
session.save(orderDetail1);
session.save(orderDetail2);
session.save(orderMaster);
tx.commit();
}catch(Exception e) {
if(tx != null) {
tx.rollback();
}
throw e;
}finally {
if(session != null) {
session.close();
}
}
}
public static void query() {
Session session = null;
try{
session = HibernateUtil.getSession();
OrderDetail orderDetail = (OrderDetail) session.get(OrderDetail.class, 1L);
System.out.println(orderDetail.getProductCode() + "," + orderDetail.getProductQty());
// 级联查询出OrderMaster
OrderMaster orderMaster = orderDetail.getOrderMaster();
System.out.println(orderMaster.getOrderNo());
}catch(Exception e) {
throw e;
}finally {
if(session != null) {
session.close();
}
}
}
}
package com.xigua.test;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.xigua.domain.OrderDetail;
import com.xigua.domain.OrderMaster;
import com.xigua.utils.HibernateUtil;
public class Test4 {
public static void main(String args[]) {
save();
query();
}
public static void save() {
Session session = null;
Transaction tx = null;
try{
session = HibernateUtil.getSession();
tx = session.beginTransaction();
OrderDetail orderDetail1 = new OrderDetail();
orderDetail1.setProductCode("18013-02");
orderDetail1.setProductQty(23);
OrderDetail orderDetail2 = new OrderDetail();
orderDetail2.setProductCode("18013-02");
orderDetail2.setProductQty(23);
Set<OrderDetail> orderDetails = new HashSet<OrderDetail>();
orderDetails.add(orderDetail1);
orderDetails.add(orderDetail2);
OrderMaster orderMaster = new OrderMaster();
orderMaster.setOrderNo("201408100000001");
// 级联保存OrderDetail
orderMaster.setOrderDetails(orderDetails);
session.save(orderDetail1);
session.save(orderDetail2);
session.save(orderMaster);
tx.commit();
} catch (Exception e) {
if(tx != null) {
tx.rollback();
}
throw e;
} finally {
if(session != null) {
session.close();
}
}
}
public static void query() {
Session session = null;
try{
session = HibernateUtil.getSession();
OrderMaster orderMaster = (OrderMaster) session.get(OrderMaster.class, 1L);
System.out.println(orderMaster.getOrderNo());
// 级联查询出OrderDetail
Set<OrderDetail> orderDetails = orderMaster.getOrderDetails();
if(orderDetails != null && orderDetails.size() > 0) {
for(OrderDetail orderDetail : orderDetails) {
System.out.println(orderDetail.getProductCode() + "," + orderDetail.getProductQty());
// 结果验证,这里不能通过getOrderMaster()去拿订单主表信息 orderDetail.getOrderMaster() 是null值
System.out.println(orderDetail.getOrderMaster());
}
}
}catch(Exception e) {
throw e;
}finally {
if(session != null) {
session.close();
}
}
}
}