一对多关系是表提出来的概念,两张表之间会存在这种,前提是有外键关联。
例如:省份和城市
如果设计类,怎样描述省份和城市之间的一对多关系
省份类里包含多个城市对象,使用 Set集合来描述
城市类里包含一个省份对象。
使用Hibernate开发时,如果表中存在一对多关系,而且这些表一起选择生成映射,则会自动生成包含一对多关系的类。
这里建立两张表(省份和城市)
CREATE TABLE province (
id number(8) primary key ,
title varchar2(20) not null
);
INSERT INTO province VALUES (1,'江苏');
INSERT INTO province VALUES (2,'北京');
INSERT INTO province VALUES (3,'广东');
CREATE TABLE city (
id number(8) primary key ,
title varchar2(50) not null,
province_id int not null,
foreign key (province_id) references province (id) on delete cascade
);
INSERT INTO city VALUES (1,'南通',1);
INSERT INTO city VALUES (2,'南京',1);
INSERT INTO city VALUES (3,'海淀区',2);
INSERT INTO city VALUES (4,'朝阳区',2);
INSERT INTO city VALUES (5,'广州',3);
INSERT INTO city VALUES (6,'深圳',3);
commit;
在MyEclipse中,两张表一起选择,生成映射
选择使用自增长方式来加入主键。
注意,要两张表一起。
生成好的类中存在了一对多的关系,看下vo类,这里get/set方法省略
public class City implements java.io.Serializable {
private Integer id;
private Province province;
private String title;
}
public class Province implements java.io.Serializable {
private Integer id;
private String title;
private Set cities = new HashSet(0);
}
映射文件中也说明了这个关系。
province映射:
<?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="org.liky.otm.pojo.Province" table="PROVINCE" schema="SUNXUN">
<id name="id" type="java.lang.Integer">
<column name="ID" precision="8" scale="0" />
<generator class="increment" />
</id>
<property name="title" type="java.lang.String">
<column name="TITLE" length="20" not-null="true" />
</property>
<!--
在Province中包含一个名称为cities的Set集合.
-->
<set name="cities" inverse="true">
<!--
关联外键是PROVINCE_ID
-->
<key>
<column name="PROVINCE_ID" precision="22" scale="0" not-null="true" />
</key>
<!--
当前类(Province)于City类存在一对多关系
-->
<one-to-many class="org.liky.otm.pojo.City" />
</set>
</class>
</hibernate-mapping>
注:Inverse=”true”在这里的意思是:关联关系交给对方对象进行维护。
Province和City之间的关联关系是由外键字段province_id来维护的,该字段在city表中,修改city表时,才能修改该字段。
因此可以说,关联关系是由City表来维护的。因此,对于Province来说,关联关系是交给对方(City)来维护的。
city映射:<?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="org.liky.otm.pojo.City" table="CITY" schema="SUNXUN">
<id name="id" type="java.lang.Integer">
<column name="ID" precision="8" scale="0" />
<generator class="increment" />
</id>
<!--
表示当前类(City)与Province存在多对一关系,关联的变量名为province,关联字段名为PROVINCE_ID
-->
<many-to-one name="province" class="org.liky.otm.pojo.Province" fetch="select">
<column name="PROVINCE_ID" precision="22" scale="0" not-null="true" />
</many-to-one>
<property name="title" type="java.lang.String">
<column name="TITLE" length="50" not-null="true" />
</property>
</class>
</hibernate-mapping>
注:
Fetch表示Session的get和load的关联查询方式。
当使用Session.get来按主键查询City对象时,会自动关联查询出Province,fetch则是关联查询是通过inner join还是分开两条sql完成。
Fetch=”select”时,分开两条sql语句,分别查询两张表数据,而且默认使用懒汉式加载。
Fetch=”join”时,则一次将数据全部查询出来。
如果查询省份或城市信息,可以自动关联取得其他的内容。
例如:
根据省份,查询所有省份下的城市列表。
public class Test {
public static void main(String[] args) {
// City c = (City) HibernateSessionFactory.getSession().get(City.class,
// 3);
// System.out.println(c.getTitle());
// System.out.println(c.getProvince().getTitle());
String hql = "FROM Province";
Query query = HibernateSessionFactory.getSession().createQuery(hql);
List<Province> all = query.list();
Iterator<Province> iter = all.iterator();
while (iter.hasNext()) {
Province p = iter.next();
System.out.println(p.getTitle());
Iterator<City> iter2 = p.getCities().iterator();
while (iter2.hasNext()) {
City c = iter2.next();
System.out.println(" |-" + c.getTitle());
}
}
}
}
实现省份城市的下拉列表选择:
先实现省份的查询全部的后台方法。只需要在ProvinceDAO写一个findAll的方法并实现
然后在页面上加入超连接,进入Action,完成查询
<span style="white-space:pre"> </span><center>
<a href="province!list.action">省份城市关联列表</a>
</center>
完成Action中的list方法。
public class ProvinceAction extends ActionSupport {
private List<Province> allProvince;
public String list() throws Exception {
allProvince = ServiceFactory.getIProvinceServiceInstance().list();
return "list";
}
配置struts:
<span style="white-space:pre"> </span><package name="root" namespace="/" extends="struts-default">
<action name="province" class="org.liky.otm.action.ProvinceAction">
<result name="list">/pages/province/province_list.jsp</result>
</action>
</package>
完成页面的列表显示功能。
两层嵌套循环
<span style="white-space:pre"> </span><select>
<c:forEach var="p" items="${allProvince}">
<option value="${p.id }">${p.title }</option>
<c:forEach var="c" items="${p.cities}">
<option value="${c.id }"> |- ${c.title }</option>
<span style="white-space:pre"> </span></c:forEach>
</c:forEach>
</select>
出现懒汉式加载异常。
解决方法:
1) 不关连接(不推荐)
2) 不使用懒汉式,需要修改映射文件。
<set name="cities" lazy="false" order-by="id desc" inverse="true">