zoukankan      html  css  js  c++  java
  • Hibernate查询

       

    9.1  Hibernate数据查询

    数据查询与检索是Hibernate的一个亮点。Hibernate的数据查询方式主要有3种,它们是:

    l         Hibernate Query Language(HQL)

    l         Criteria Query

    l         Native SQL

    下面对这3种查询方式分别进行讲解。

    9.1.1  Hibernate Query Language(HQL)

    Hibernate Query Language(HQL)提供了十分强大的功能,推荐大家使用这种查询方式。HQL具有与SQL语言类似的语法规范,只不过SQL针对表中字段进行查 询,而HQL针对持久化对象,它用来取得对象,而不进行update、delete和insert等操作。而且HQL是完全面向对象的,具备继承、多态和 关联等特性。

    1.from子句

    from字句是最简单的HQL语句,例如 from Student,也可以写成select s from Student s。它简单地返回Student类的所有实例。

    除了Java类和属性的名称外,HQL语句对大小写并不敏感,所以在上一句HQL语句中,from与FROM是相同的,但是Student与student 就不同了,所以上述语句写成from student就会报错。下列程序演示如何通过执行from语句取得所有的Student对象。

    Query query = session.createQuery(“from Student”);

    List list = query.list();

    for (int i=0;i<list.size(); i++)

    {

        Student stu = (Student)list.get(i);

        System.out.println(stu.getName());

    }

    如果执行HQL语句“from Student, Course”,并不简单地返回两个对象,而是返回这两个对象的的笛卡儿积,这类似于SQL语句中字段的全外连接。在实际应用中,像“from Student, Course”这样的语句几乎不会出现。

    2.select子句

    有时并不需要得到对象的所有属性,这时可以使用select子句进行属性查询,例如,select s.name from Student s。下面程序演示如何执行这个语句:

    Query query = session.createQuery(“select s.name from Student s”);

    List list = query.list();

    for (int i=0;i<list.size(); i++) {

        String name = (String)list.get(i);

        System.out.println(ame());

    }

    如果要查询两个以上的属性,查询结果会以数组的方式返回,如下所示:

    Query query = session.createQuery(“select s.name, s.sex from Student as s”);

    List list = query.list();

    for (int i=0;i<list.size(); i++) {

        Object obj[] = (Object[])list.get(i);

        System.out.println(ame(obj[0] + “的性别是:” +obj[1]));

    }

    在使用属性查询时,由于使用对象数组,操作和理解都不太方便,如果将一个object[]中所有成员封装成一个对象就方便多了。下面的程序将查询结果进行了实例化:

    Query query = session.createQuery(“select new Student(s.name, s.sex) from Student s”);

    List list = query.list();

    for (int i=0;i<list.size(); i++) {

        Student stu = (Student)list.get(i);

        System.out.println(stu.getName());

    }

    要正确运行以上程序,还需要在Student类中加入一个如下的构造函数:

    public Student(String name, String sex)

    {

        this.name = name;

        this.sex = sex;

    }

    3.统计函数查询

    可以在HQL中使用函数,经常使用的函数有:

    l         count():统计记录条数

    l         min():求最小值

    l         max():求最大值

    l         sum():求和

    l         age():求平均值

    例如,要取得Student实例的数量,可以编写如下HQL语句:

    select count(*) from Student

    取得Student的平均年龄的HQL语句如下:

    select avg(s.age) from Student as s

    可以使用distinct去除重复数据:

    select distinct s.age from Student as s

    4.where子句

    HQL也支持子查询,它通过where子句实现这一机制。where子句让用户缩小要返回的实例的列表范围,例如下面语句会返回所有名字为“Bill”的Student实例:

    Query query = session.createQuery("from Student as s where s.name='Bill' ");

    where子句允许出现的表达式包括了SQL中可以使用的大多数情况:

    l         数学操作:+,-,*,/

    l         真假比较操作:=,>=,<=,<>,!=,like

    l         逻辑操作:and,or, not

    l         字符串连接:||

    l         SQL标量函数:例如upper()和lower()

    如果子查询返回多条记录,可以用以下的关键字来量化:

    l         all:表示所有的记录。

    l         any:表示所有记录中的任意一条。

    l         some:与any用法相同。

    l         in:与any等价。

    l         exists:表示子查询至少要返回一条记录。

    例如,下面语句返回所有学生的年龄都大于22的班级对象:

    from Group g where 22<all (select s.age from g.students s)

    下述语句返回在所有学生中有一个学生的年龄等于22的班级:

    from Group g where 22=any (select s.age from g.students s)

    或者

    from Group g where 22=some (select s.age from g.students s)

    或者

    from Group g where 22 in (select s.age from g.students s)

    5.order by 子句

    查询返回的列表可以按照任何返回的类或者组件的属性排序:

    from Student s order by s.name asc

    asc和desc是可选的,分别代表升序或者降序。

    6.连接查询

    与SQL查询一样, HQL也支持连接查询,如内连接、外连接和交叉连接。

    l         inner join:内连接

    l         left outer join:左外连接

    l         right outer join:右外连接

    l         full join:全连接,但不常用

    下面重点讲解内连接查询,左外连接和右外连接查询和内连接大同小异,而全连接几乎不怎么使用。

    inner join可以简写为join,例如在查询得到Group对象时,内连接取得对应的Student对象,实现的程序如下。

    ……//打开Session,开启事务

    Student  stu = null;  //声明Student实例

    Group  group = null; //声明Group实例

    Query query = session.createQuery("from Group g join g.students");

    List list = query.list();

    Object obj[] = null;  //声明对象数组

    for(int i=0;i<list.size();i++)  {

        obj = (Object[])list.get(i); //取得集合中的第i个数组

        group = (Group)obj[0];  //group是数组中第一个对象

        stu = (Student)obj[1];   //stu是数组中第二个对象

        System.out.println(stu.getName() + "属于:" +group.getName() );

    }

        ……//提交事务,关闭Session

    9.1.2  Criteria Query方式

    当查询数据时,人们往往需要设置查询条件。在SQL或HQL语句中,查询条件常常放在where子句中。此外,Hibernate还支持Criteria 查询(Criteria Query),这种查询方式把查询条件封装为一个Criteria对象。在实际应用中,使用Session的createCriteria()方法构建一 个org.hibernate.Criteria实例,然后把具体的查询条件通过Criteria的add()方法加入到Criteria实例中。这样, 程序员可以不使用SQL甚至HQL的情况下进行数据查询,如例程9-1所示。

    例程9-1  Criteria应用实例

    ------------------------------------------------------------------------------------------

    Criteria cr = session.createCriteria(Student.class); //生成一个Criteria对象

    cr.add(Restrictions.eq("name", "Bill"));//等价于where name=’Bill’

    List list = cr.list();

    Student stu = (Student)list.get(0);

    System.out.println(stu.getName());

    1.常用的查询限制方法

    在例程9-1中,Restrictions.eq()方法表示equal,即等于的情况。Restrictions类提供了查询限制机制。它提供了许多方法,以实现查询限制。这些方法及其他一些criteria常用查询限制方法列于表9-1中。

    表9-1  Criteria Query常用的查询限制方法

    方    法

    说    明

    Restrictions.eq()

    equal,=

    Restrictions.allEq()

    参数为Map对象,使用key/value进行多个等于的对比,相当于多个Restrictions.eq()的效果

    Restrictions.gt()

    greater-than, >

    Restrictions.lt()

    less-than, <

    Restrictions.le()

    less-equal, <=

    Restrictions.between()

    对应SQL的between子句

    Restrictions.like()

    对应SQL的like子句

    Restrictions.in()

    对应SQL的in子句

    Restrictions.and()

    and关系

    Restrictions.or()

    or关系

    Restrictions.isNull()

    判断属性是否为空,为空返回true,否则返回false

    Restrictions.isNotNull()

    与Restrictions.isNull()相反

    Order.asc()

    根据传入的字段进行升序排序

    Order.desc()

    根据传入的字段进行降序排序

    MatchMode.EXACT

    字符串精确匹配,相当于“like 'value'”

    MatchMode.ANYWHERE

    字符串在中间位置,相当于“like '%value%'”

    MatchMode.START

    字符串在最前面的位置,相当于“like 'value%'”

    MatchMode.END

    字符串在最后面的位置,相当于“like '%value'”

    例1:查询学生名字以t开头的所有Student对象。

    Criteria cr = session.createCriteria(Student.class);

    cr.add(Restrictions.like(“name”, “t%”))

    List list = cr.list();

    Student stu = (Student)list.get(0);

    或者使用另一种方式:

    Criteria cr = session.createCriteria(Student.class);

    cr.add(Restrictions.like(“name”, “t”, MatchMode.START))

    List list = cr.list();

    Student stu = (Student)list.get(0);

    例2:查询学生姓名在Bill, Jack和Tom之间的所有Student对象。

    String[] names = {“Bill”, “Jack”, “Tom”}

    Criteria cr = session.createCriteria(Student.class);

    cr.add(Restrictions.in(“name”, names))

    List list = cr.list();

    Student stu = (Student)list.get(0);

    例3:查询学生的年龄age等于22或age为空(null)的所有Student对象。

    Criteria cr = session.createCriteria(Student.class);

    cr.add(Restrictions.eq(“age”, new Integer(22));

    cr.add(Restrictions.isNull(“age”));

    List list = cr.list();

    Student stu = (Student)list.get(0);

    例4:查询学生姓名以字母F开头的所有Student对象,并按姓名升序排序。

    Criteria cr = session.createCriteria(Student.class);

    cr.add(Restrictions.like(“name”, “F%”);

    cr.addOrder(Order.asc(“name”));

    List list = cr.list();

    Student stu = (Student)list.get(0);

    Tips

     

    调用Order.asc的方法应是Criteria的addOrder()方法。

    2.连接限制

    在Criteria 查询中使用FetchMode来实现连接限制。在HQL语句中,可以通过fetch关键字来表示预先抓取(Eager fetching),如下所示:

    from Group g

    left join fetch g.students s

    where g.name like ' 05'

    可以使用Criteria的API完成同样的功能,如下所示:

    Criteria cr = session.createCriteria(Group.class);

    cr.setFetchMode(“students”, FetchMode.EAGER);

    cr.add(Restrictions.like(“name”, “2005”, MatchMode.END))

    List list = cr.list();

    以上两种方式编写的代码,都使用相同的SQL语句完成它们的功能,如下所示:

    select g.*, s.* from Group g

    left outer join Student s

    on g.id = s.group_id

    where g.name like ' 05'

    9.1.3  Native SQL查询

    本地SQL查询(Native SQL Query)指的是直接使用本地数据库(如Oracle)的SQL语言进行查询。它能够扫清你把原来直接使用SQL/JDBC 的程序迁移到基于 Hibernate应用的道路上的障碍。

    Hibernate3允许你使用手写的SQL来完成所有的create、update、delete和load操作(包括存储过程)。

    1.创建一个基于SQL的Query

    Native SQL查询是通过SQLQuery接口来控制的,它是通过调用Session.createSQLQuery()方法来获得的,例如:

    String sql = "select {s.*} from t_student s where s.age>22";

    SQLQuery slqQuery = session.createSQLQuery(sql);

    sqlQuery.addEntity("s", Student.class);

    List list = sqlQuery.list();

    for (int i=0;list.size();i++) {

    Student stu = (Student)list.get(i);

    System.out.println(stu.getAge() +" "+ stu.getName());

    }

    createSQLQuery(String sql)利用传入的SQL参数构造一个SQLQuery实例(SQLQuery是Query的子接口)。使用这个方法时,还需要传入查询的实体类,因此要配合SQLQuery的addEntity()方法一起使用。

    addEntity()方法是将实体类别与别名联系在一起的方法,此方法的定义如下:

    public SQLQuery addEntity(String alias, Class entityClass)

    {}号用来引用数据表的别名,例如以上代码中{s.*}表示使用s来作为t_student表的别名。

    2.命名SQL查询

    与HQL的命名查询相似,也可以将本地的SQL查询语句定义在映射文件中,然后像调用一个命名HQL查询一样直接调用命名SQL查询。

    例如在Student.hbm.xml中定义一个命名SQL查询,如下所示:

    <hibernate-mapping>

    <class name="Student" table="student" lazy="false">

    ……

    </class>

    <sql-query name="QueryStudents">

    <![CDATA[

                 select {s.*} from t_student s where s.age>22

    ]]>

    <return alias="s" class="Student"/>

    </sql-query>

    </hibernate-mapping>

    <sql- query>元素是<hibernate-mapping>元素的一个子元素。利用<sql-query>元素的子元素<return>指定别名与实体类相关联。配合映射文件中的定义,编写如下代码来调用这个命名SQL查询:

    Query query = session.getNamedQuery(“QueryStudents”);

    List list = query.list();

    for (int i=0;list.size();i++) {

    Student stu = (Student)list.get(i);

    System.out.println(stu.getAge() + “ ”+ stu.getName());

    }

    也可以在命名查询中设定查询参数,如下所示:

    ……

    <sql-query name=”QueryStudents”>

        <![CDATA[

            select {s.*} from t_student s where s.age>:age

        ]]>

        <return alias=”s” class=”Student”/>

    </sql-query>

    …..

    编写如下代码来调用这个命名SQL查询,并且把查询中定义的参数传入:

    Query query = session.getNamedQuery(“QueryStudents”);

    query.setInteger(“age”,22);

    List list = query.list();

    for (int i=0;list.size();i++) {

    Student stu = (Student)list.get(i);

    System.out.println(stu.getAge() + “ ”+ stu.getName());

    }

    3.自定义insert、update和delete语句

    Hibernate3.x 的映射文件中新添了<sql-insert>、<sql-update> 和<sql-delete>3个标记。可以使用这3个标记自定义自己的insert、update和delete语句,例如在 Student.hbm.xml中定义这些语句如下:

    <hibernate-mapping>

    <class name="Student" table="student" lazy="false">

    <id name="id" unsaved-value="null" type="string" column="id">

        <generator class="uuid.hex"/>

    <property name="name" type="string" />

    <property name="age" type="int" />

    <sql-insert> <!--insert语句-->

        insert into t_student(name, age, id) values(?,?,?)

        </sql-insert>

        <sql-update> <!--update语句-->

        update t_student set name=?, age=? where id=?

        </sql-update>

        <sql-delete> <!--delete语句-->

            delete from t_student where id=?

    </sql-delete>

    </class>

    </hibernate-mapping>

    对于上述文件中自定义的SQL语句,要注意以下几点。

    l         insert和update语句中定义的字段必须和映射文件声明的属性相对应,一个都不能少。

    l         在insert和update语句中,属性出现的顺序必须和映射文件中声明的顺序一致。

    l         在insert语句中,主键id总是放在最后。

    在程序中实现以上自定义的insert语句如下:

    ……

    Student stu = new Student();

    stu.setName(“Bill”);

    stu.setAge(22);

    session.save(stu);

    运行上述程序,控制台显示的信息如下:

    Hibernate: insert into t_student(name,age,id) values(?,?,?)

    如果不想在insert或update语句中包括所有属性,则可以在属性定义时,加上insert="false"或update="false",如下所示:

    <property name=”name” type=”string” insert=”false” update=”false” />

        <sql-insert>  insert into t_student(age, id) values(?,?)  </sql-insert>

    <sql-update> update t_student set age=? where id=?  </sql-update>

    实例:

    9.2  利用关联关系操纵对象

    数据对象之间关联关系有一对一、一对多及多对多关联关系。在数据库操作中,数据对象之间的关联关系使用JDBC处理很困难。本节讲解如何在 Hibernate中处理这些对象之间的关联关系。本节使用到4个类,它们分别是Student(学生)、Card(学生证)、Group(班级)和 Course(课程),它们之间的关联关系如图9-1所示。这些实体存在级联(cascade)问题。例如,当删除一个班级的信息时,还要删除该班的所有 学生的基本信息。如果直接使用JDBC执行这种级联操作,会非常烦琐。Hibernate通过把实体对象之间关联关系及级联关系在映射文件中声明,比较简 便地解决了这类级联操作问题。

    图9-1  对象关联图

    9.2.1  一对一关联关系的使用

    一对一关系在实际生活中是比较常见的,例如学生与学生证的关系,通过学生证可以找到学生。一对一关系在Hibernate中的实现有两种方式,分别是主键关联和外键关联。

    1.以主键关联

    主键关联的重点是,关联的两个实体共享一个主键值。例如,Student与Card是一对一关系,它们在数据库中对应的表分别是t_student和 t_card。它们共用一个主键值id,这个主键可由t_student表或t_card表生成。问题是如何让另一张表引用已经生成的主键值呢?例 如,t-student表填入了主键id的值,t_card表如何引用它?这需要在Hibernate的映射文件中使用主键的foreign生成机制。

    为了表示Student与Card之间的一对一关联关系,在Student和Card的映射文件Student.hbm.xml和Card.hbm.xml中都要使用<one-to-one>标记,如例程9-2所示。

    例程9-2  Student.hbm.xml

    -----------------------------------------------------------------------------------------------

    <?xml version="1.0"?>

    <!DOCTYPE hibernate-mapping PUBLIC

        "-//Hibernate/Hibernate Mapping DTD//EN"

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

    <hibernate-mapping>

    <class name="test.Student" table="T_STUDENT" lazy="true"><!-- 把类与表关联起来-->

    <id name="id" column="id" type="int">

    <generator class="increment" />

    </id>

    <property name="name" column="NAME" type="string" />

    <!--property name="card_id" column="CARD_ID" type="int" /--> <!--映射学生证号-->

    <property name="sex" column="SEX" type="string" />

    <property name="age" column="AGE" type="int" />

    <one-to-one  name="card"  class="test.Card"

        fetch="join" cascade="all"  />

    </class>

    </hibernate-mapping>

    <class>元素的lazy属性设定为true,表示延迟加载,如果lazy的值设置为false,则表示立即加载。下面对立即加载和延迟加载这两个概念进行说明。

    l         立即加载:表示Hibernate在从数据库中取得数据,组装好一个对象(比如学生1)后,会立即再从数据库取得数据,组装此对象所关联的对象(例如学生证1)。

    l         延迟加载:表示Hibernate在从数据库中取得数据,组装好一个对象(比如学生1)后,不会立即再从数据库取得数据,组装此对象所关联的对象(例如学生证1),而是等到需要时,才会从数据库取得数据,组装此关联对象。

    <one-to-one>元素的cascade属性表明操作是否从父对象级联到被关联的对象,它的取值如下。

    l         none:在保存、删除或修改对象时,不对其附属对象(关联对象)进行级联操作。这是默认设置。

    l         save-update:在保存、更新当前对象时,级联保存、更新附属对象(临时对象、游离对象)。

    l         delete:在删除当前对象时,级联删除附属对象。

    l         all:在所有情况下均进行级联操作,即包含save-update和delete操作。

    l         delete-orphan:删除和当前对象解除关系的附属对象。

    <one-to-one>元素的fetch属性的可选值是join和select,默认值是select。当fetch属性设定为join时,表示连接抓取(Join fetching : Hibernate通过 在SELECT语句使用OUTER JOIN(外连接)来获得对象的关联实例或者关联集合。 当fetch属性设定为select时,表示查询抓取(Select fetching:需要另外发送一条 SELECT 语句抓取当前对象的关联实体或集合。

    例程9-3中<one-to-one>元素的cascade属性设置为“all”,表示增加、删除及修改Student对象时,都会级联增加、删除和修改Card对象。

    例程9-3  Card.hbm.xml

    -----------------------------------------------------------------------------------------------

    <?xml version="1.0"?>

    <!DOCTYPE hibernate-mapping PUBLIC

        "-//Hibernate/Hibernate Mapping DTD//EN"

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

    <hibernate-mapping>

    <class name="test.Card" table="t_card" lazy="true"><!-- 把类与表关联起来-->

    <id name="id" column="id">

    <generator class="foreign" >

        <param name="property">student</param>

        </generator>

    </id>

    <one-to-one name="student"  class="test.Student" constrained="true"/>

    <property name="name" column="name" type="string" />

    <!-- one-to-one name="student"  class="test.Student" constrained="true"/-->

    </class>

    </hibernate-mapping>

    在例程9-3中,Card.hbm.xml的主键id使用外键(foreign)生成机制,引用代号为“student”对象的主键作为Card表的主键 和外键。student在该映射文件的<one-to-one>元素中进行了定义,它是Student对象的代号。<one-to- one>元素的属性Constrained="true"表示Card引用了student的主键作为外键。

    需要特别注意的是,Student类中要相应地加入一对get/set方法:

    public Card getCard() {

        return this.card;   

        }

        public void setCard(Card card) {

    this.card = card;

    }

    在Card类中也要相应地加入一对get/set方法:

    public Student getStudent() {

        return this.stu;

        }

    public void setStudent(Student stu) {

        this.stu = stu;

    }

    在客户端测试程序中操纵Student和Card对象的方法如例程9-4所示。

    例程9-4  客户端测试程序

    package test;

    import org.hibernate.*;

    import org.hibernate.cfg.*;

    import java.io.File;

    import java.util.List;

    public class Test {

        public static void main(String[] args) {

                     

            File file = new File("D:\eclipse3.2\workspace\HibernateTest\hibernate.cfg.xml");

                     

            Configuration  conf = new Configuration().configure(file);

                     

            SessionFactory  sf = conf.buildSessionFactory();

                     

            Session session = sf.openSession();

                     

            Transaction tx = session.beginTransaction();

                     

            //新建Student对象

            Student stu = new Student();

                stu.setName("Walker");

                stu.setSex("male");

                stu.setAge(22);

                //新建Card对象

                Card card = new Card();

                card.setName("Walker");

                               

            //设置Student对象与Card对象之间的关联

            stu.setCard(card);

            card.setStudent(stu); //此句不能省略,否则card将不知从何处取得主键值

            

            try {

                session.save(stu);

            tx.commit();

            session.close();

            System.out.println("Data have been inserted into DB.");

            } catch (HibernateException e) {

                e.printStackTrace();

                tx.rollback();

            session.close();

            }   

        }

    }

    运行以上代码后,将会在t_student表和t_card表中插入相应的数据。

    2.以外键关联

    以外键关联的要点是:两个实体各自有不同的主键,但其中一个实体有一个外键引用另一个实体的主键。例如,假如Student和Card是外键关联的一对一 关系,它们在数据库中相应的表分别是t_student表和t_card表,t_student表有一个主键id,t_card表有一个主键id和一个外 键 stu_id,此外键对应student表的主键id。

    Student的映射文件Student.hmb.xml见例程9-2。但Card的映射文件Card.hbm.xml要做相应变动,如例程9-5所示。

    例程9-5  Card.hbm.xml

    ----------------------------------------------------------------------------------------------------------------------

    <?xml version="1.0"?>

    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"

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

    <hibernate-mapping>

    <class name="test.Card"  table="T_CARD" lazy= "true"><!--把类与表关联起来-->

    <id name="id" >

    <generator class="increment" ><!--不再是foreign了-->

        </generator>

    </id>

    <property name="name" column="NAME" type="string" />

    <many-to-one  name="student"  class="Student" column="stu_id"

        unique="true"/> <!--唯一的多对一,实际上变成一对一关系了-->

    </class>

    </hibernate-mapping>

    在例程9-5中,<many-to-one>元素的name属性声明外键关联对象的代号,class属性声明该外键关联对象的类,column属性声明该外键在数据表中对应的字段名,unique属性表示使用DDL为外键字段生成一个唯一约束。

    以外键关联对象的一对一关系,其实本质上变成了一对多的双向关联了,应直接按照一对多和多对一的要求编写它们的映射文件。当<many-to-one>元素的unique属性设定为true,多对一的关系实际上变成了一对一的关系。

    在客户端程序中操纵外键关联一对一关系的对象的方法见例程9-4。

    9.2.2  一对多关联关系的使用

    一对多关系很常见,例如父亲和孩子、班级与学生的关系就是很好的一对多的关系。在实际编写程序时,一对多关系有两种实现方式:单向关联和双向关联。单向的 一对多关系只需在一方进行映射配置,而双向的一对多需要在关联的双方进行映射配置。下面以Group(班级)和Student(学生)为例讲解如何配置一 对多的关系。

    1.单向关联

    单向的一对多关系只需在一方进行映射配置,所以我们只配置Group(班级)的映射文件Group.hbm.xml,如例程9-6所示。

    例程9-6  Group.hbm.xml

    <?xml version="1.0"?>

    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"

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

    <hibernate-mapping>

    <class name="test.Group" table="T_GROUP" lazy="true"><!--把类与表关联起来-->

    <id name="id" column="ID"type="int">

    <generator class="increment" >

        </generator>

    </id>

    <property name="name" column="NAME" type="string"

        update="true" insert="true" />

    <set  name="students"

        table="T_STUDENT"

        lazy="false"

        inverse="false"

        cascade="all"

        sort="unsorted"

    <key column="ID"/>

    <one-to-many class="test.Student"/>

    </set>

    </class>

    </hibernate-mapping>

    在以上映射文件中,<property>元素的insert属性表示被映射的字段是否出现在SQL的 INSERT语句中;update属性表示被映射的字段是否出现在SQL的 UPDATE语句中。

    <set>元素描述的字段(本例中为students)对应的类型为java.util.Set,它的各个属性的含义如下。

    l         name:字段名,本例的字段名为students,它属于java.util.Set类型。

    l         table:关联表名,本例中,students的关联数据表名是t_student。

    l         lazy:是否延迟加载,lazy=false表示立即加载。

    l         inverse:用于表示双向关联中的被动方的一端,inverse的值为false的一方负责维护关联关系。默认值为false。本例中Group将负责维护它与Student之间的关联关系。

    l         cascade:级联关系;cascade=all表示所有情况下均进行级联操作,即包含save-update和delete操作。

    l         sort:排序关系,其可选取值为unsorted(不排序)、natural(自然排序)、comparatorClass(由某个实现了java.util.comparator接口的类型指定排序算法)。

    <key>子元素的column属性指定关联表(本例中t_student表)的外键,<one-to-many>子元素的class属性指定了关联类的名字。

    此外,在Group类中增加如下get/set方法:

    private Set students;

        public Set getStudents() {

            return this.students;

        }

        public void setStudents(Set stu) {

            this.students = stu;

    }

    假如我们想为一个班级添加一个学生对象,实现的代码如下:

    Transaction tx = session.beginTransaction();

    Student stu = new Student();

    stu.setName("Walker");

    stu.setSex("male");

    stu.setAge(22);

    group.getStudents().add(stu);

    session.save(group);

    tx.commit();

    2.双向关联

    如果要设置一对多双向关联,那么还需要在“多”方的映射文件中使用<many-to-one>标记。例如,在Group与Student一对 多的双向关联中,除了Group的映射文件Group.hbm.xml和Group类进行设置和修改外,还需要在Student的映射文件 Student.hbm.xm中加入:

    <many-to-one

            name="group"

            class="test.Group"

            cascade="none"

            outer-join="auto"

            update="true"

            insert="true"

            column="ID"

            />

    name、class等属性前面已经解释过了,这里只说明insert和update属性。insert和update设定是否对column属性指定的关联字段进行insert和update操作。在Student类还要相应添加一对get/set方法:

    public Group getGroup() {

        return this.group;

        }

        public void setGroup(Group g) {

            this.group = g;

        }

    此外,把Group.hbm.xml(如例程9-6所示)中的<set>元素的inverse属性的值设定为true,如下所示。

    <set  name="students" table="T_STUDENT" lazy="false"

        inverse="true" cascade="all" sort="unsorted">

    <key column="ID"/>

    <one-to-many class="Student"/>

    </set>

    当 Group.hmb.xml中<set>元素的inverse属性的值设定为false时,Group和Student之间的关联关系由 Group维护,Group负责将自己的id告诉Student,然后Hibernate发送update语句去更新记录。但现在inverse的值设定 为true后,Group和Student之间的关联关系转由Student来维护,由Student自动去取得Group的id,而这个Student 取得Group的id的动作,其实就是完成一个“学生添加到班级”的动作。

    9.2.3  多对多关联关系的使用

    Student(学生)和Course(课程)的关系就是多对多的关系。在映射多对多关系时,需要另外使用一个连接表(例如,Student_Course)。 Student_Course表包含2个字段:CourseId和StuId。此外,在它们的映射文件中使用<many-to-many>标记。

    Student的映射文件Student.hbm.xml中加入以下描述信息:

    <set  name="courses"  table=" Student_Course" lazy="false"

        inverse="false" cascade="save-update" >

    <key column="StuId"/>

    <many-to-many class="test.Course" column="CourseId" />

    </set>

    相应地,Course的映射文件Course.hbm.xml加入以下描述信息:

    <set  name="students"  table=" Student_Course" lazy="false"

    inverse="true" cascade="save-update" >

    <key column="CourseId"/>

    <many-to-many class="test.Student" column="StuId"  />

    </set>

    1.添加关联关系

    首先让我们编一个程序来看看一个名为Bill的学生选择了什么课程:

    ……

    //获得包含Bill的Student对象

    Student stu = (Student) session.createQuery(“from Student s where s.name =

    ‘Bill’ ”) .uniqueResult();

    List ls = new ArrayList(stu.getCourses());

    for(int i=0; i<ls.size(); i++) {

        Course course = (Course)ls.get(i);  //获得Course对象

        System.out.println(course.getName()); //打印Bill所选课程的清单

    }

    …..

    现在Bill还想选修business课程,这对于程序员来说只是为Bill添加了一个到business的关联,也就是说在student_course表中新添一条记录,而T_Student 和T_Course表都不用变更。

    ……

    Student stu = (Student) session.createQuery(“from Student s where s.name = ‘Bill’ ”) .uniqueResult();

    Course course = (Course) session.createQuery(“from Course c where c.name =

    ‘business’ ”) .uniqueResult();

    //设置stu与course的相互关系

    stu.getCourses().add(course);

    course.getStudents().add(stu);

    …..

    2.删除关联关系

    删除关联关系比较简单,直接调用对象集合的remove()方法删除不要的对象即可。例如,要从学生Bill的选修课清单中删除politics和chemistry两门课,程序如下:

    …….

    Student stu = (Student) session.createQuery("from Student s where s.name = 'Bill' ") .uniqueResult();

    Course course1 = (Course) session.createQuery("from Course c where c.name =

    'politics' ") .uniqueResult();

    Course course2 = (Course) session.createQuery("from Course c where c.name =

    'chemistry' ") .uniqueResult();

    stu.getCourse().remove(course1); //删除politics课程

    stu.getCourse().remove(course2); //删除chemisty课程

    …….

    运行以上语句将从student_course表中删除这两条记录,但T_Student和T_Course表没有任何变化。

    0

    0

    阅读(1407) 评论 (1) 收藏(0) 转载(2) 喜欢 打印举报
    已投稿到:
    前一篇:云空间
    • 新浪网友

      文章很好,就是配色太接近了,读着累。。。

      2012-7-1  18:48回复(0)

    发评论
     
     
     
    • 灌水
    • 赞
    • 美好
    • 顶
    • 顶
    • 顶
    • 开心
    • 路过

    登录名: 密码: 找回密码 注册

       

    验证码: 请点击后输入验证码 收听验证码

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

    < 前一篇云空间
      

    新浪BLOG意见反馈留言板 不良信息反馈 电话:4006900000 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有

     

  • 相关阅读:
    Python 集合
    Python sorted()
    CodeForces 508C Anya and Ghosts
    CodeForces 496B Secret Combination
    CodeForces 483B Friends and Presents
    CodeForces 490C Hacking Cypher
    CodeForces 483C Diverse Permutation
    CodeForces 478C Table Decorations
    CodeForces 454C Little Pony and Expected Maximum
    CodeForces 313C Ilya and Matrix
  • 原文地址:https://www.cnblogs.com/CooderIsCool/p/4745774.html
Copyright © 2011-2022 走看看