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

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

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

例如:学生选课

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

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

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

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

[java] view plain copy
  1. CREATE TABLE T_User (  
  2.        userid         varchar2(40)        primary key ,   
  3.        real_name      varchar2(20)        not null,  
  4.        password       varchar2(32)        not null,  
  5.        regist_date    date                default sysdate,  
  6.        last_login_date         date                             
  7. );  
  8. INSERT INTO t_USER (userid,real_name,password)   
  9. VALUES ('zhangsan','张三','123');  
  10. commit;  
  11.   
  12. CREATE TABLE course (  
  13.        cid           number(8)          primary key ,  
  14.        title         varchar2(50)       not null                     
  15. );  
  16. INSERT INTO course VALUES (1,'Java编程');  
  17. INSERT INTO course VALUES (2,'JavaWeb');  
  18. INSERT INTO course VALUES (3,'Java面向对象编程');  
  19. INSERT INTO course VALUES (4,'Android ');  
  20. commit;  
  21.   
  22. CREATE TABLE <span style="color:#cc0000;">user_course</span> (  
  23.        userid             varchar2(40)      ,  
  24.        course_id          number(8)         ,  
  25.        primary key (userid,course_id),  
  26.        <span style="color:#cc0000;">foreign key (userid) references t_user (userid) on delete cascade ,  
  27.        foreign key (course_id) references course (id) on delete cascade </span>  
  28. );  

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

(经典)Hibernate多对多关系映射(五)_第1张图片

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

(经典)Hibernate多对多关系映射(五)_第2张图片

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

查看生成的vo实体类:

[java] view plain copy
  1. public class TUser implements java.io.Serializable {  
  2.     private String userid;  
  3.     private String realName;  
  4.     private String password;  
  5.     private Date registDate;  
  6.     private Date lastLoginDate;  
  7.     private Set courses = new HashSet(0);  
[java] view plain copy
  1. public class Course implements java.io.Serializable {  
  2.   
  3.     private Integer id;  
  4.     private String title;  
  5.     private Set TUsers = new HashSet(0);//可以发现,互相包含了Set集合。  
映射文件中也描述了这个关系。

TUser映射:

[java] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  3. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  4. <hibernate-mapping>  
  5.     <class name="org.liky.pojo.TUser" table="T_USER" schema="SUNXUN">  
  6.         <id name="userid" type="java.lang.String">  
  7.             <column name="USERID" length="40" />  
  8.             <generator class="assigned"></generator>  
  9.         </id>  
  10.         <property name="realName" type="java.lang.String">  
  11.             <column name="REAL_NAME" length="20" not-null="true" />  
  12.         </property>  
  13.         <property name="password" type="java.lang.String">  
  14.             <column name="PASSWORD" length="32" not-null="true" />  
  15.         </property>  
  16.         <property name="registDate" type="java.util.Date">  
  17.             <column name="REGIST_DATE" length="7" />  
  18.         </property>  
  19.         <property name="lastLoginDate" type="java.util.Date">  
  20.             <column name="LAST_LOGIN_DATE" length="7" />  
  21.         </property>  
  22.         <!--   
  23.             在TUser中包含一个名称为courses的Set集合,该数据是依据User_COURSE表关联查询出来的.  
  24.         -->  
  25.         <set name="courses" table="USER_COURSE" schema="SUNXUN">  
  26.             <!--   
  27.                 中间表中通过USERID与当前表(TUSER)外键关联  
  28.             -->  
  29.             <key>  
  30.                 <column name="USERID" length="40" not-null="true" />  
  31.             </key>  
  32.             <!--   
  33.                 中间表通过COURSE_ID与Course外键关联,因此当前类与Course是多对多关系  
  34.             -->  
  35.             <many-to-many entity-name="org.liky.pojo.Course">  
  36.                 <column name="COURSE_ID" precision="8" scale="0" not-null="true" />  
  37.             </many-to-many>  
  38.         </set>  
  39.     </class>  
  40. </hibernate-mapping>  
Course映射:
[java] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  3. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  4. <hibernate-mapping>  
  5.     <class name="org.liky.pojo.Course" table="COURSE" schema="SUNXUN">  
  6.         <id name="id" type="java.lang.Integer">  
  7.             <column name="ID" precision="8" scale="0" />  
  8.             <generator class="increment"></generator>  
  9.         </id>  
  10.         <property name="title" type="java.lang.String">  
  11.             <column name="TITLE" length="50" not-null="true" />  
  12.         </property>  
  13.         <set name="TUsers" inverse="true" table="USER_COURSE" schema="SUNXUN">  
  14.             <key>  
  15.                 <column name="COURSE_ID" precision="8" scale="0" not-null="true" />  
  16.             </key>  
  17.             <many-to-many entity-name="org.liky.pojo.TUser">  
  18.                 <column name="USERID" length="40" not-null="true" />  
  19.             </many-to-many>  
  20.         </set>  
  21.     </class>  
  22. </hibernate-mapping>  

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

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

二、实现选课功能:


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

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

[java] view plain copy
  1. public class TUserDAOImpl implements ITUserDAO {  
  2.     public boolean isLogin(TUser user) throws Exception {  
  3.         String hql = "FROM TUser AS u WHERE u.userid = ? AND u.password = ?";  
  4.         Query query = HibernateSessionFactory.getSession().createQuery(hql);  
  5.   
  6.         query.setString(0, user.getUserid());  
  7.         query.setString(1, user.getPassword());  
  8.   
  9.         List<User> allUser = query.list();  
  10.   
  11.         if (allUser != null && allUser.size() > 0) {  
  12.             TUser result = (TUser) allUser.get(0);  
  13.   
  14.             // 将结果设置到user中,根据按引用传递,外面的对象也自动设置好了属性.  
  15.             user.setRealName(result.getRealName());  
  16.             user.setRegistDate(result.getRegistDate());  
  17.             user.setLastLoginDate(result.getLastLoginDate());  
  18.               
  19.             // 取得该用户所选择的所有课程信息  
  20.             user.setCourses(result.getCourses());  
  21.             return true;  
  22.         }  
  23.         return false;  
  24.     }  
  25. }  

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

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

[java] view plain copy
  1. <pre code_snippet_id="329570" snippet_file_name="blog_20140506_7_1927285" name="code" class="java"><set name="courses" lazy="false" order-by="course_id" table="USER_COURSE" schema="SUNXUN">    </pre>  
  2. <pre></pre>  
  3. <pre></pre>  
  4. <pre></pre>  
  5. <pre></pre>  

下面实现选课功能。

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

先加入连接

[java] view plain copy
  1. <a href="user!selectCoursePre.action">选课</a>      

完成Action中的操作

[java] view plain copy
  1. <span style="white-space:pre">  </span>private List<Course> allCourse;  
  2.     <pre code_snippet_id="329570" snippet_file_name="blog_20140506_9_6224637" name="code" class="java">public String selectCoursePre() {  
  3.         allCourse = ServiceFactory.getITUserServiceInstance().selectCoursePre();  
  4.   
  5.         // 取得之前选择的课程信息,先取得当前登陆用户  
  6.         TUser loginUser = (TUser) ServletActionContext.getRequest()  
  7.                 .getSession().getAttribute("user");  
  8.         Set<Course> userCourse = loginUser.getCourses();  
  9.         int index = 0;  
  10.         courseIds = new int[userCourse.size()];  
  11.         Iterator<Course> iter = userCourse.iterator();  
  12.         while(iter.hasNext()) {  
  13.             Course c = iter.next();  
  14.             courseIds[index++] = c.getId();  
  15.         }  
  16.         return "select";  
  17.     }</pre>  
  18. <pre></pre>  
  19. 编写struts:  
  20. <p></p>  
  21. <pre code_snippet_id="329570" snippet_file_name="blog_20140506_10_2397390" name="code" class="java"><result name="select">/pages/user/user_select_course.jsp</result></pre>  
  22. <p></p>  
  23. <p>完成页面显示</p>  
  24. <p></p>  
  25. <pre code_snippet_id="329570" snippet_file_name="blog_20140506_11_2473837" name="code" class="java"><span style="white-space:pre">      </span><center>  
  26.             用户登陆成功,当前用户为: ${user.realName } <br/>  
  27.             <br/>  
  28.             <br/>  
  29.             <hr/>  
  30.             <s:form action="user!selectCourse.action" method="post" theme="simple" namespace="/">  
  31.                 请选择课程:   
  32.                 <s:checkboxlist list="allCourse" name="courseIds" listKey="id" listValue="title"></s:checkboxlist>  
  33.             <span style="white-space:pre">  </span><!--  
  34.                  如果使用的是普通表单,必须在页面上两层迭代循环,而且还要在标签中嵌套标签完成。  
  35. <span style="white-space:pre">              </span><c:forEach var="c" items="${allCourse}">                 
  36.                     <input type="checkbox" name="courseIds" value="${c.id }"   
  37.                     <c:forEach var="cid" items="${courseIds}">  
  38.                         ${cid==c.id?"checked":"" }   
  39.                     </c:forEach>  
  40.                      /> ${c.title }    
  41.                 </c:forEach>  
  42. <span style="white-space:pre">      </span>-->  
  43.                 <br/>  
  44.                 <s:submit value="提交"></s:submit>  
  45.             </s:form>  
  46.         </center></pre>  
  47. <p></p>  
  48. <p>提交后,需要在Action中接收选择的课程编号,并将这些课程加入到当前登陆的用户信息中。</p>  
  49. 最后需要修改这个用户。  
  50. <p></p>  
  51. <pre code_snippet_id="329570" snippet_file_name="blog_20140506_12_6694742" name="code" class="java">// 接收用户所选择的课程编号  
  52.     private int[] courseIds;  
  53.     private String message;  
  54.     private String url;  
  55.   
  56.     public String selectCourse() {  
  57.         // 取得当前登陆用户  
  58.         TUser loginUser = (TUser) ServletActionContext.getRequest()  
  59.                 .getSession().getAttribute("user");  
  60.   
  61.         // 将原有的取消  
  62.         loginUser.getCourses().clear();  
  63.   
  64.         // 把选择的课程信息加入到这个User对象中  
  65.         for (int i = 0; i < courseIds.length; i++) {  
  66.             int id = courseIds[i];  
  67.             Course c = new Course();  
  68.             c.setId(id);  
  69.             loginUser.getCourses().add(c);  
  70.         }  
  71.   
  72.         // 修改  
  73.         ServiceFactory.getITUserServiceInstance().selectCourse(loginUser);  
  74.           
  75.         message = "选课成功";  
  76.         url = "pages/suc.jsp" ;  
  77.   
  78.         return "forward";  
  79.     }</pre>最后在struts中编写跳转到成功的页面。  
  80. <p></p>  
  81. <pre></pre>  
  82. <pre></pre>  
  83. <pre></pre> 

你可能感兴趣的:((经典)Hibernate多对多关系映射(五))