Hibernate的多对一的关系查询
配置步骤
1.创建一个可以存储多个表数据的实体类,多对一的关系
//联系人和客户是多对一的关系,意味着一个联系人对应一个客户
//所以,一个联系人里面只有一个可以存储一个客户数据的属性就可以了。
//所以使用Customer的引用
private Customer customer;
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
2.将查询的多个表的数据封装这个实体累的对象里面,通过配置来说实现。
<many-to-one name="customer" column="lkm_cust_id"></many-to-one>
注意:,但是这样的方式会引起字段冲突,两个外键字段名都相同,程序不知道要对哪一个进行操作
代码
持久化类
Customer
public class Customer {
private Long custId;//bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
private String custName;//varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
private String custSource;//varchar(32) DEFAULT NULL COMMENT '客户信息来源',
private String custIndustry;//varchar(32) DEFAULT NULL COMMENT '客户所属行业',
private String custLevel;//varchar(32) DEFAULT NULL COMMENT '客户级别',
get()/set()......
}
Linkman
public class Linkman {
private Long lkmId;//主键
private String lkmName;
private Long lkmCustId;//外键
private String lkmGender;
private String lkmPhone;
private String lkmMobile;
private String lkmEmail;
private String lkmQq;
private String lkmPosition;
private String lkmMemo;
private Customer customer;
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
get()/set()......
}
Linkman.hbm.xml
many-to-one是声明关联文件
name属性:设置对应的实体类的属性名
- column属性:设置多对一的外键字段
- insert属性:设置实体类对应的属性在插入的时候忽略
- update属性:设置实体类对应的属性在更新的时候忽略
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class name="com.entity.Linkman" table="cst_linkman">
<id name="lkmId" column="lkm_id">
<generator class="identity"></generator>
</id>
<property name="lkmName" column="lkm_name"></property>
<!-- 原因:同一个文件里面,如果出现了两个以上的column,在更新的时候和插入的时候,不知道以哪个字段的值为准 -->
<!-- 解决方案:
1.删除一个外键字段
2.将一个外键字段设置为,插入和更新的时候忽略它的值 insert="false" 和 update="false" -->
<!-- <property name="lkmCustId" column="lkm_cust_id" /> -->
<property name="lkmGender" column="lkm_gender"></property>
<property name="lkmPhone" column="lkm_phone"></property>
<property name="lkmMobile" column="lkm_mobile"></property>
<property name="lkmEmail" column="lkm_email"></property>
<property name="lkmQq" column="lkm_qq"></property>
<property name="lkmPosition" column="lkm_position"></property>
<property name="lkmMemo" column="lkm_memo"></property>
<!--
配置多对一的关系
many-to-one是声明关联文件
name属性:设置对应的实体类的属性名
column属性:设置多对一的外键字段
insert属性:设置实体类对应的属性在插入的时候忽略
update属性:设置实体类对应的属性在更新的时候忽略
-->
<many-to-one name="customer" column="lkm_cust_id" insert="false" update="false"></many-to-one>
<!-- <many-to-one name="customer" column="lkm_cust_id" insert="false" update="false"></many-to-one>-->
</class>
</hibernate-mapping>
推荐使用直接注释外键属性的配置。
<!-- <property name="lkmCustId" column="lkm_cust_id" /> -->
Customer.hbm.xml没有变化
hibernate.cfg.xml继续加载两个映射文件
注意
Linkman映射文件
为什么一对多和多对一,配置的的都是外键,不用配置主键。
- 答:原因,因为主键本身就有一个单独的标签标签唯一了。而外键没有单独的标签的。
注意:
1. 必须知道为什么导致字段冲突。
- 因为出现两个属性对应一个数据库的字段column。那么就导致在插入或者更新的时候,程序不知道以哪个属性的值作为正确的数据插入或者更新到数据库。
必须知道如何解决字段冲突的问题
方式1:直接删除外键属性的配置
- 缺陷:必须在插入的时候,创建一个对象来设置外键值。
方式2:保留一个单独的属性用于插入和更新使用的外键,将设置了外键的字段(customer)设置为
insert=”false” update=”false”
,意思就是查询和更新时,忽略该属性的值。- 缺陷:级联插入或级联更新会导致外键字段没有值,所以不能使用级联插入或者级联更新
如果要保证功能的完整性,需要支持级联增加,使用多对的关系作为外键属性。直接删除外键属性 (推荐使用)
如果不需要级联增加,那么就可以使用一个属性单独作为外键
直接删除外键属性的配置
- 如果需要插入数据,就必须创建一个对象来设置外键值
@Test
public void insert(){
//获得操作对象
Session session = HibernateUtils.getSession();
//开启事务
Transaction transaction = session.beginTransaction();
//封装数据
Linkman linkman = new Linkman();
linkman.setLkmName("马云");
//创建一个客户表的实体类对象来设置外键值,而且外键值是必须存在的
Customer customer = new Customer();
customer.setCustId(3L);
linkman.setCustomer(customer);
//保存数据
session.save(linkman);
//提交事务
transaction.commit();
session.close();
}
查询和更新时,忽略该属性的值。
如果选择保留一个单独的属性用于插入和更新使用的外键,将设置了外键的字段(customer)设置为insert=”false” update=”false”
,查询和更新时,忽略该属性的值
- 那么他的缺陷是级联插入或级联更新会导致外键字段没有值,丢失了值
如果修改后再次使用上面的方法会报错,所以直接给外键值赋值就可以了
@Test
public void insert2(){
//获得操作对象
Session session = HibernateUtils.getSession();
//开启事务
Transaction transaction = session.beginTransaction();
//封装数据
Linkman linkman = new Linkman();
linkman.setLkmName("马云");
//直接给外键赋值
linkman.setLkmCustId(3L);
//保存数据
session.save(linkman);
//提交事务
transaction.commit();
session.close();
}