级联分为一对多,多对一单向,多对多双向关联。一般情况下,我们只会用到前两种情况,多对多用的较少。我这里使用省市区三级联查来实现级联的操作。简单来说,一对多就是一个省下面有多个市,一个市下面有多个县。多对一是刚好反过来的。
首先是使用配置文件的情况下,关联类,生成的hbm.xml文件中显示如下:
<hibernate-mapping>
<class name="com.qy.domain.Province" table="province" schema="java1807">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="code" column="code"/>
<property name="name" column="name"/>
<!--
name:当前类的属性名
column:从表中的外键名
foreign-key:主表中的被参照字段
property-ref:主表中被参照字段的属性名
class:从表的类
lazy:true 使用懒加载机制 默认
lazy:false 放弃懒加载
inverse:true 放弃主控权
inverse:false 默认
-->
<set name="cities" cascade="all" lazy="true" inverse="true">
<key column="provincecode" foreign-key="code" property-ref="code"></key>
<one-to-many class="com.qy.domain.City"></one-to-many>
</set>
</class>
</hibernate-mapping>
hibernate.hbm.xml配置如下:
<mapping class="com.qy.domain.Province"></mapping>
<mapping class="com.qy.domain.City"></mapping>
<mapping class="com.qy.domain.Area"></mapping>
使用注解:
就是把mapping配置文件跟换掉。注解方式不需要在xxx.hbm.xml把实体类与表进行映射。而采用在实体类中进行注解。
注意:
(1):如果实体类属性名与表字段名不一致的时候,要么都注解在属性前,要么都注解在get方法前。不能部分注解在属性前,部分注解在方法前。
(2):如果实体类属性名与表字段名一致的时候,可以部分注解在属性前,部分注解在方法前。
(3):如果在实体类中某些属性不注解:(属性和get都不写注解),默认为表字段名与实体类属性名一致。
(4):如果实体类的某个成员属性不需要对这个成员属性进行映射))
(5):表名称可以在实体类前进行注解。
(6):所有这些注解在:javax.persistence包下。而不是在hibernate包中
<mapping resource="Area.hbm.xml"/>
<mapping resource="City.hbm.xml"/>
<mapping resource="Province.hbm.xml"/>
实体类配置如下:
@Entity
@Table(name = "province",schema = "java1807")
public class Province implements Serializable {
private int id;
private String code;
private String name;
private Set<City> cities=new HashSet<>();
@Id
@Column(name ="id")
@GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Column(name="code")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Column(name="name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(cascade= CascadeType.ALL,mappedBy ="province")
public Set<City> getCities() {
return cities;
}
public void setCities(Set<City> cities) {
this.cities = cities;
}
public Province() {
}
public Province(int id, String code, String name) {
this.id = id;
this.code = code;
this.name = name;
}
@Override
public String toString() {
return "Province{" +
"id=" + id +
", code='" + code + '\'' +
", name='" + name + '\'' +
'}';
}
}
多对一关联
city.hbm.xml文件
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.qy.domain.City" table="city" schema="java1807">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="code" column="code"/>
<property name="name" column="name"/>
<!--
多对一关联
name:city中属性名province
colum:city表中对应的列名
class:属性名province对应的对象类
如果通过主键关联不需要配置property-ref
如果不通过主键关联需要配置property-ref:指向Province类中参照的属性名
cascade:save-update,强制级联更新
-->
<many-to-one name="province" class="com.qy.domain.Province" property-ref="code" cascade="all">
<column name="provincecode"></column>
</many-to-one>
</class>
</hibernate-mapping>
使用注解对city进行改进,实体类配置如下:
@Entity
@Table(name="city",schema = "java1807")
public class City {
private int id;
private String code;
private String name;
/*private String provincecode;*/
private Province province;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Column(name="code")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/* public String getProvincecode() {
return provincecode;
}
public void setProvincecode(String provincecode) {
this.provincecode = provincecode;
}*/
@ManyToOne(targetEntity = Province.class)
@JoinColumn(name="provincecode",referencedColumnName = "code")
public Province getProvince() {
return province;
}
public void setProvince(Province province) {
this.province = province;
}
@Override
public String toString() {
return "City{" +
"id=" + id +
", code='" + code + '\'' +
", name='" + name + '\'' +
'}';
}
}
这是我写的测试类,对级联进行增删查改功能。
public class Test2 {
@Test
public void testQuary(){
Session session = HibernateUtill.getCurrentSession();
List<Province> list = session.createQuery("from Province").list();
HibernateUtill.sessionClose(session);
}
@Test
public void testSave(){
Session session = HibernateUtill.getCurrentSession();
session.beginTransaction();
Province p = new Province();
p.setName("腾飞省");
p.setCode("830000");
Set<City> cities = new HashSet<City>();
City c1 = new City();
c1.setName("腾飞市1");
c1.setCode("830100");
City c2 = new City();
c2.setName("腾飞市2");
c2.setCode("830200");
cities.add(c1);
cities.add(c2);
p.setCities(cities);
session.save(p);
session.getTransaction().commit();
HibernateUtill.sessionClose(session);
}
@Test
public void testUpdate(){
Session session = HibernateUtill.getCurrentSession();
session.beginTransaction();
Province p = session.get(Province.class,39);
p.setName("腾飞市");
Set set = p.getCities();
Iterator it = set.iterator();
int i =1;
while(it.hasNext()){
City c = (City) it.next();
c.setName("腾飞"+i++);
}
session.update(p);
session.getTransaction().commit();
HibernateUtill.sessionClose(session);
}
@Test
public void testDelete(){
Session session = HibernateUtill.getCurrentSession();
session.beginTransaction();
Province p = session.get(Province.class,39);
session.delete(p);
session.getTransaction().commit();
HibernateUtill.sessionClose(session);
}
注解相对于配置文件更加简单,但还是没有配置文件好理解,建议新手还是先回使用配置文件。