(经典)Hibernate多对多关系映射(五)

多对多关系是产生在三张表的关系中的,必须有一张中间表,必须保证中间表只有两个字段,必须是复合主键,必须是另两张表的外键。

一、用多对多关系来设计类

例如:学生选课

这里只创建学生和课程类,中间表不生成对应的pojo。

类中通过以下方式表示关系:

1)  学生会选择多门课程,因此在学生类中包含了多个课程类的对象,使用Set集合来保存。

2)  一门课程有多个学生选择,因此课程类中也要包含多个学生的对象,使用Set集合来保存。

CREATE TABLE T_User (
       userid         varchar2(40)        primary key , 
       real_name      varchar2(20)        not null,
       password       varchar2(32)        not null,
       regist_date    date                default sysdate,
       last_login_date         date                           
);
INSERT INTO t_USER (userid,real_name,password) 
VALUES ('zhangsan','张三','123');
commit;

CREATE TABLE course (
       cid           number(8)          primary key ,
       title         varchar2(50)       not null                   
);
INSERT INTO course VALUES (1,'Java编程');
INSERT INTO course VALUES (2,'JavaWeb');
INSERT INTO course VALUES (3,'Java面向对象编程');
INSERT INTO course VALUES (4,'Android ');
commit;

CREATE TABLE user_course (
       userid             varchar2(40)      ,
       course_id          number(8)         ,
       primary key (userid,course_id),
       foreign key (userid) references t_user (userid) on delete cascade ,
       foreign key (course_id) references course (id) on delete cascade 
);

三张表一起选择,来生成映射。


注意,选中多对多关系的多选框,同时,由于多张表的主键生成方式不同,因此建议在下一步单独为每张表选择。


每张表单独选择主键生成方式,course 采用increment,T_user采用的是asigned;

查看生成的vo实体类:

public class TUser implements java.io.Serializable {
	private String userid;
	private String realName;
	private String password;
	private Date registDate;
	private Date lastLoginDate;
	private Set courses = new HashSet(0);
public class Course implements java.io.Serializable {

	private Integer id;
	private String title;
	private Set TUsers = new HashSet(0);//可以发现,互相包含了Set集合。
映射文件中也描述了这个关系。

TUser映射:

<?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.pojo.TUser" table="T_USER" schema="SUNXUN">
        <id name="userid" type="java.lang.String">
            <column name="USERID" length="40" />
            <generator class="assigned"></generator>
        </id>
        <property name="realName" type="java.lang.String">
            <column name="REAL_NAME" length="20" not-null="true" />
        </property>
        <property name="password" type="java.lang.String">
            <column name="PASSWORD" length="32" not-null="true" />
        </property>
        <property name="registDate" type="java.util.Date">
            <column name="REGIST_DATE" length="7" />
        </property>
        <property name="lastLoginDate" type="java.util.Date">
            <column name="LAST_LOGIN_DATE" length="7" />
        </property>
        <!-- 
        	在TUser中包含一个名称为courses的Set集合,该数据是依据User_COURSE表关联查询出来的.
        -->
        <set name="courses" table="USER_COURSE" schema="SUNXUN">
        	<!-- 
        		中间表中通过USERID与当前表(TUSER)外键关联
        	-->
            <key>
                <column name="USERID" length="40" not-null="true" />
            </key>
            <!-- 
            	中间表通过COURSE_ID与Course外键关联,因此当前类与Course是多对多关系
            -->
            <many-to-many entity-name="org.liky.pojo.Course">
                <column name="COURSE_ID" precision="8" scale="0" not-null="true" />
            </many-to-many>
        </set>
    </class>
</hibernate-mapping>
Course映射:

<?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.pojo.Course" table="COURSE" schema="SUNXUN">
        <id name="id" type="java.lang.Integer">
            <column name="ID" precision="8" scale="0" />
            <generator class="increment"></generator>
        </id>
        <property name="title" type="java.lang.String">
            <column name="TITLE" length="50" not-null="true" />
        </property>
        <set name="TUsers" inverse="true" table="USER_COURSE" schema="SUNXUN">
            <key>
                <column name="COURSE_ID" precision="8" scale="0" not-null="true" />
            </key>
            <many-to-many entity-name="org.liky.pojo.TUser">
                <column name="USERID" length="40" not-null="true" />
            </many-to-many>
        </set>
    </class>
</hibernate-mapping>

Inverse的意思是 关联关系由对方进行维护。

多对多关系中,关键关系是中间表,需要根据业务逻辑判断,现在是学生选课功能,学生是主动方,课程被动方,因此可以说,学生在维护中间表的数据,也就是说学生维护两者的关联关系,对于课程来说,关联关系由对方(学生)进行维护。

二、实现选课功能:


选课前需要先登陆系统(学生的选课信息只存在于user_course表中,只能通过登录来区别个人),这里可以直接使用之前写好的登陆功能来完成登陆。

但登陆的DAO需要设置该学生对应的课程信息。

public class TUserDAOImpl implements ITUserDAO {
	public boolean isLogin(TUser user) throws Exception {
		String hql = "FROM TUser AS u WHERE u.userid = ? AND u.password = ?";
		Query query = HibernateSessionFactory.getSession().createQuery(hql);

		query.setString(0, user.getUserid());
		query.setString(1, user.getPassword());

		List<User> allUser = query.list();

		if (allUser != null && allUser.size() > 0) {
			TUser result = (TUser) allUser.get(0);

			// 将结果设置到user中,根据按引用传递,外面的对象也自动设置好了属性.
			user.setRealName(result.getRealName());
			user.setRegistDate(result.getRegistDate());
			user.setLastLoginDate(result.getLastLoginDate());
			
			// 取得该用户所选择的所有课程信息
			user.setCourses(result.getCourses());
			return true;
		}
		return false;
	}
}

测试登陆功能时,也提示懒汉式异常,因为根据学生查找了课程信息。

解决方法也是修改映射文件。

<set name="courses" lazy="false" order-by="course_id" table="USER_COURSE" schema="SUNXUN">    




下面实现选课功能。

需要先完成课程的查询功能,取得全部课程,在页面上显示。

先加入连接

<a href="user!selectCoursePre.action">选课</a>	

完成Action中的操作

	private List<Course> allCourse;
	
public String selectCoursePre() {
		allCourse = ServiceFactory.getITUserServiceInstance().selectCoursePre();

		// 取得之前选择的课程信息,先取得当前登陆用户
		TUser loginUser = (TUser) ServletActionContext.getRequest()
				.getSession().getAttribute("user");
		Set<Course> userCourse = loginUser.getCourses();
		int index = 0;
		courseIds = new int[userCourse.size()];
		Iterator<Course> iter = userCourse.iterator();
		while(iter.hasNext()) {
			Course c = iter.next();
			courseIds[index++] = c.getId();
		}
		return "select";
	}

编写struts:

<result name="select">/pages/user/user_select_course.jsp</result>

完成页面显示

		<center>
			用户登陆成功,当前用户为: ${user.realName } <br/>
			<br/>
			<br/>
			<hr/>
			<s:form action="user!selectCourse.action" method="post" theme="simple" namespace="/">
				请选择课程: 
				<s:checkboxlist list="allCourse" name="courseIds" listKey="id" listValue="title"></s:checkboxlist>
            	<!--
                 如果使用的是普通表单,必须在页面上两层迭代循环,而且还要在标签中嵌套标签完成。
				<c:forEach var="c" items="${allCourse}">				
					<input type="checkbox" name="courseIds" value="${c.id }" 
					<c:forEach var="cid" items="${courseIds}">
						${cid==c.id?"checked":"" } 
					</c:forEach>
					 /> ${c.title }  
				</c:forEach>
		-->
				<br/>
				<s:submit value="提交"></s:submit>
			</s:form>
		</center>

提交后,需要在Action中接收选择的课程编号,并将这些课程加入到当前登陆的用户信息中。

最后需要修改这个用户。

// 接收用户所选择的课程编号
	private int[] courseIds;
	private String message;
	private String url;

	public String selectCourse() {
		// 取得当前登陆用户
		TUser loginUser = (TUser) ServletActionContext.getRequest()
				.getSession().getAttribute("user");

		// 将原有的取消
		loginUser.getCourses().clear();

		// 把选择的课程信息加入到这个User对象中
		for (int i = 0; i < courseIds.length; i++) {
			int id = courseIds[i];
			Course c = new Course();
			c.setId(id);
			loginUser.getCourses().add(c);
		}

		// 修改
		ServiceFactory.getITUserServiceInstance().selectCourse(loginUser);
		
		message = "选课成功";
		url = "pages/suc.jsp" ;

		return "forward";
	}
最后在struts中编写跳转到成功的页面。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值