Hibernate多对多关系映射

来源:互联网 发布:vue.js radio checked 编辑:程序博客网 时间:2024/05/22 17:36

多对多关系并不是两张表的关系,而是三张表的关系,而且要求必须有一个中间表,中间表必须只有两个字段,必须为复合主键,必须包含外键。

如果以上条件都满足,MyEclipse在三张表一起选择时,就可以生成多对多关系映射。

 

类一般只生成两个类,例如:学生选课中,只生成学生和课程类,关系使用以下方式描述:

1)  学生类中保存着该学生选择的所有课程对象,使用Set集合来保存。

2)  课程类中保存着所有选择此课程的学生对象,使用Set集合来保存。

 

建立数据表

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
);

使用t_user,course和user_course表,完成映射:

many to many 前面打勾:



由于t_user使用assigned,course使用increment,因此,这里不统一选择方式。

而是在后面单独选择。

同时,注意将允许使用多对多的多选框选中。

可以在这里单独选择方式。

public class TUser implements java.io.Serializable {

 

    private Stringuserid;

    private StringrealName;

    private Stringpassword;

    private DateregistDate;

    private DatelastLoginDate;

    private Set courses = new HashSet(0);

public class Course implements java.io.Serializable {

 

    private Integerid;

    private Stringtitle;

    private Set TUsers = newHashSet(0);

类中确定了集合关系

映射文件里也描述了多对多关系:

<?xmlversion="1.0"encoding="utf-8"?>

<!DOCTYPEhibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

    <classname="org.liky.pojo.TUser"table="T_USER"schema="SUNXUN">

        <idname="userid"type="java.lang.String">

            <columnname="USERID"length="40"/>

            <generatorclass="assigned"></generator>

        </id>

        <propertyname="realName"type="java.lang.String">

            <columnname="REAL_NAME"length="20"not-null="true"/>

        </property>

        <propertyname="password"type="java.lang.String">

            <columnname="PASSWORD"length="32"not-null="true"/>

        </property>

        <propertyname="registDate"type="java.util.Date">

            <columnname="REGIST_DATE"length="7"/>

        </property>

        <propertyname="lastLoginDate"type="java.util.Date">

            <columnname="LAST_LOGIN_DATE"length="7"/>

        </property>

        <!--

        User中包含一个名称为coursesSet集合,数据是根据中间表USER_COURSE来关联取得的.

        -->

        <setname="courses"table="USER_COURSE"schema="SUNXUN">

        <!--

             中间表中通过USERID与当前类(User)关联

        -->

            <key>

                <columnname="USERID"length="40"not-null="true"/>

            </key>

            <!--

              中间表还通过COURSE_IDCourse对象关联,联系起来出现的是多对多关系。

            -->

            <many-to-manyentity-name="org.liky.pojo.Course">

                <columnname="COURSE_ID"precision="8"scale="0"not-null="true"/>

            </many-to-many>

        </set>

    </class>

</hibernate-mapping>

 

<?xmlversion="1.0"encoding="utf-8"?>

<!DOCTYPEhibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<!--

    Mapping file autogenerated by MyEclipse Persistence Tools

-->

<hibernate-mapping>

    <classname="org.liky.pojo.Course"table="COURSE"schema="SUNXUN">

        <idname="id"type="java.lang.Integer">

            <columnname="ID"precision="8"scale="0"/>

            <generatorclass="increment"></generator>

        </id>

        <propertyname="title"type="java.lang.String">

            <columnname="TITLE"length="50"not-null="true"/>

        </property>

        <setname="TUsers"inverse="true"table="USER_COURSE"schema="SUNXUN">

            <key>

                <columnname="COURSE_ID"precision="8"scale="0"not-null="true"/>

            </key>

            <many-to-manyentity-name="org.liky.pojo.TUser">

                <columnname="USERID"length="40"not-null="true"/>

            </many-to-many>

        </set>

    </class>

</hibernate-mapping>

 


可以发现有一边的配置中出现了inverse=”true”,这个配置表示关联关系由对方进行维护。

多对多关系中,实际上,关联关系指的就是中间表,需要根据业务想清楚谁来维护中间表,这里实现的功能是学生选课,也就是说学生是主动的一方,应该由学生添加自己所选的课程,也就是说中间表数据应该由学生来维护的。

因此可以说,关联关系应该由学生来维护,对于课程来说,关联关系就应该由对方(学生)来进行维护。

    public static void main(String[] args) {

       // 学生选课操作实际上是对学生的修改操作,而不是添加.

       // 先取得一个学生

       TUser user = (TUser) HibernateSessionFactory.getSession().get(

              TUser.class,"zhangsan");

       // // 以下int值就是该学生选择的课程编号

       // int[] courseIds = { 2, 4, 5 };

       // // 将课程id关联到学生对象中

       // for (int i = 0; i < courseIds.length; i++) {

       // int id = courseIds[i];

       // Course c = new Course();

       // c.setId(id);

       // // 把课程加入到学生选择的课程集合里

       // user.getCourses().add(c);

       // }

 

       // 如果想取消这些课程,直接将集合清空

       user.getCourses().clear();

 

       // 取消一部分,再添加一部分

       int[] courseIds = { 2, 3,5 };

       // 将课程id关联到学生对象中

       for (int i = 0; i < courseIds.length; i++) {

           int id = courseIds[i];

           Course c = new Course();

           c.setId(id);

           // 把课程加入到学生选择的课程集合里

           user.getCourses().add(c);

       }

 

       // 调用学生的修改

       HibernateSessionFactory.getSession().update(user);

 

       Transaction tx = HibernateSessionFactory.getSession()

              .beginTransaction();

       tx.commit();

       HibernateSessionFactory.closeSession();

 

    }

 



多对多关系应用——选课功能

首先,先要实现用户的登陆功能,当用户登陆后,列出所有课程供用户选择。

 

登陆功能之前已经实现过了,因此直接将后台代码拷贝过来即可。

登陆同时,注意,需要将之前选择的课程内容取得,并保存到user里

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;

    }

 

}

 

 

登陆成功后,用户可以看到选课的连接,点这个连接,进入选课页面,选课前,需要先查询出所有课程,列表显示。

<ahref="tuser!selectCoursePre.action">选课</a>     

编写Action的方法,在这里查询所有课程信息。

    public String selectCoursePre()throws Exception {

       allCourse = ServiceFactory.getITUserServiceInstance().selectCoursePre();

 

       return"select";

    }

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

页面显示所有课程列表,通过多选框让用户选择。

       <center>

           用户登陆成功,当前登陆用户为: ${user.realName}

           <br/>

           <hr/>

           <br/>

           <s:formaction="tuser!selectCourse.action"method="post"namespace="/"theme="simple">

              可选课程:<s:checkboxlistlist="allCourse"listKey="id"listValue="title"name="courseIds"></s:checkboxlist>

              <br/>

              <s:submitvalue="提交"></s:submit>           

           </s:form>

       </center>

提交后,完成User的修改操作,注意,需要将课程信息合并到User对象里。

    public String selectCourse()throws Exception {

       // 先取得当前登陆用户信息

       TUser loginUser = (TUser) ServletActionContext.getRequest()

              .getSession().getAttribute("user");

 

       // 设置该用户选择的课程

       loginUser.getCourses().clear();

 

       for (int i = 0; i <courseIds.length; i++) {

           int id =courseIds[i];

           Course c = new Course();

           c.setId(id);

           // 将课程合并到User对象中

           loginUser.getCourses().add(c);

       }

 

       ServiceFactory.getITUserServiceInstance().selectCourse(loginUser);

 

       // 将用户信息保存回Session

       ServletActionContext.getRequest().getSession().setAttribute("user",

              loginUser);

 

       return"forward";

    }

<resultname="forward">/forward.jsp</result>        

测试时,提示懒汉式异常,也需要通过设置lazy解决。

<setname="courses"lazy="false" table="USER_COURSE"schema="SUNXUN">       

 

使用时发现用户体验不好,用户无法看到当前选了哪些课程,而且没有默认选中已经选择过的课程。

在suc.jsp中显示出当前的课程。

           当前选择的课程有:

           <br/>

           <fontcolor="red">

           <c:forEachvar="c"items="${user.courses}">

              ${c.title } <br/>

           </c:forEach>

           </font>

           <hr/>

注意,在映射文件中,最好加入order-by,防止顺序改变

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

 

最后,设置默认选中已经选择的课程。

需要在选择课程之前,先取得之前选的课程信息的id值,传递到页面上。

    public String selectCoursePre()throws Exception {

       allCourse = ServiceFactory.getITUserServiceInstance().selectCoursePre();

 

       // 取得当前已经选择的课程信息

       TUser loginUser = (TUser) ServletActionContext.getRequest()

              .getSession().getAttribute("user");

       Set<Course> allSelectedCourse = loginUser.getCourses();

       if (allSelectedCourse !=null) {

           Iterator<Course> iter = allSelectedCourse.iterator();

           courseIds = new int[allSelectedCourse.size()];

           int index = 0;

           while (iter.hasNext()) {

              Course c = iter.next();

              courseIds[index++] = c.getId();

           }

       }

 

       return"select";

    }

 

如果使用普通标签,则必须使用下面两层循环的形式完成

           <formaction="tuser!selectCourse.action"method="post">

              可选课程:             

              <c:forEachvar="c"items="${allCourse}">

                  <inputtype="checkbox"name="courseIds"value="${c.id }"

                  <c:forEachvar="id"items="${courseIds}">

                     ${id == c.id?"checked":"" }

                  </c:forEach>

                  /> ${c.title } &nbsp;&nbsp;

              </c:forEach>

              <br/>

              <input type="submit" value="提交">           

           </form>
















0 0