前言:在域模型中,类与类之间最普遍的关系就是关联关系,在UML语言中关联关系是有方向的。在数据库中表与表之间也会有关联关系,本节介绍通过Hibernate映射一对多的关联关系,这是一种最普遍的关联关系。

1.数据库表的一对多关联关系

(1)示例数据库表说明
    本节使用两张表:tb_student(学生表)、tb_class(班级表),一个班级里有多个学生,而一个学生只能在一个班级里,这样构成了学生与班级的多对一关联关系。下图表述了Student与Class之间的关系:
          
(2)使用MySQL创建表
    根据上面的关系图,在MySQL数据库中的建表语句如下:
  1. CREATE TABLE tb_class
  2. (
  3. id bigint NOT NULL auto_increment COMMENT 'ID',
  4. no varchar(10) NOT NULL COMMENT '班级编号',
  5. name varchar(50) NOT NULL COMMENT '班级名称',
  6. PRIMARY KEY (id)
  7. ) COMMENT '班级信息表';
  8. CREATE TABLE tb_student
  9. (
  10. id bigint NOT NULL auto_increment COMMENT 'ID',
  11. no varchar(10) NOT NULL COMMENT '学号',
  12. name varchar(50) NOT NULL COMMENT '姓名',
  13. sex char(1) NOT NULL COMMENT '性别',
  14. birthday datetime COMMENT '出生日期',
  15. class_id bigint NOT NULL COMMENT '班级ID',
  16. PRIMARY KEY (id)
  17. ) COMMENT = '学生信息表';
    以上的建表语句没有新建外键关联,班级信息表表与学生信息表表只是有逻辑上的关联关系,在数据库中并没有外键关联,这种情况下也可以正常使用Hibernate关联关系。本文提供的创建外键的DDL语句如下:
  1. ALTER TABLE tb_student ADD CONSTRAINT fk_tb_student_tb_class_1 FOREIGN KEY (class_id) REFERENCES tb_class (id);
(3)编写对应的实体类
    以下是根据tb_class表编写的实体类ClassInfo:
  1. package model;
  2. public class ClassInfo
  3. {
  4. private Long id;
  5. private String no;
  6. private String name;
  7. private List<Student> students = new ArrayList<Student>();
  8. //省略setter、getter、toString...
  9. }
    以下是根据tb_student表编写的实体类Student:
  1. package model;
  2. import java.sql.Date;
  3. public class Student
  4. {
  5. private Long id;
  6. private String no;
  7. private String name;
  8. private String sex;
  9. private Date birthday;
  10. private ClassInfo classInfo;
  11. //省略setter、getter、toString...
  12. }
    注意:Hibernate要求在实体类中定义集合类属性时,必须把属性声明为接口类型,如:java.util.List、java.util.Set、java.util.Map。ClassInfo类的students属性就是用java.util.List接口。

2.建立多对一的单向关联关系

    多对一的单向关联关系和关系数据库中的外键参照关系最匹配了,因此如果使用单向关联关系,通常选择从Studen到Class的多对一单向关联。使用多对一的单向关联映射使用many-to-one元素,配置如下:
  1. <hibernate-mapping package="model">
  2. <class name="ClassInfo" table="tb_class">
  3. <id name="id">
  4. <generator class="native"></generator>
  5. </id>
  6. <property name="no" column="no"/>
  7. <property name="name" column="name"/>
  8. </class>
  9. </hibernate-mapping>
  1. <hibernate-mapping package="model">
  2. <class name="Student" table="tb_student">
  3. <id name="id">
  4. <generator class="native"></generator>
  5. </id>
  6. <property name="no" column="no"/>
  7. <property name="name" column="name"/>
  8. <property name="sex" column="sex"/>
  9. <property name="birthday" column="birthday"/>
  10. <many-to-one name="classInfo" column="class_id" class="model.ClassInfo" lazy="false"/>
  11. </class>
  12. </hibernate-mapping>
    关于以上many-to-one元素的配置说明如下:
    1. name:设置需要映射的实体类属性名。
    2. column:设置和实体类的属性对应的表的外键。注意:Hibernate默认此外键参照的是对应实体类的主键,在这里即是class_id参照classInfo实体类的id。
    3. class:设置需要映射的实体类属性的类型。
    4. lazy:是否使用懒加载,使用懒加载Hibernate会在你第一次访问关联的对象时才会去数据库取数据,不会立即去数据库检索与此对象关联的所有数据。
    根据以上配置编写测试程序,测试程序的代码如下:
  1. public static void main(String[] args)
  2. {
  3. Student student;
  4. Configuration cfg = new Configuration();
  5. cfg.configure();
  6. ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
  7. SessionFactory sf = cfg.buildSessionFactory(sr);
  8. System.out.println("连接数据库");
  9. Session session = sf.openSession();

  10. student=(Student) session.get(Student.class, new Long(1));
  11. System.out.println(student);
  12. System.out.println(student.getClassInfo());

  13. session.close();
  14. System.out.println("关闭数据库");
  15. System.exit(0);
  16. }
    现在还不能运行测试程序,在运行下、测试程序之前还要把新增的配置文件配置到hibernate.cfg.xml文件里,如下:
  1. <hibernate-configuration>
  2. <session-factory>
  3. <!-- 省略其他...,设置实体类到数据库的映射文件 -->
  4. <mapping resource="model/ClassInfo.hbm.xml"/>
  5. <mapping resource="model/Student.hbm.xml"/>
  6. </session-factory>
  7. </hibernate-configuration>
    运行程序,得到如下输出:
  1. 连接数据库
  2. Hibernate:
  3. select
  4. student0_.id as id1_2_0_,
  5. student0_.no as no2_2_0_,
  6. student0_.name as name3_2_0_,
  7. student0_.sex as sex4_2_0_,
  8. student0_.birthday as birthday5_2_0_,
  9. student0_.class_id as class_id6_2_0_
  10. from
  11. tb_student student0_
  12. where
  13. student0_.id=?
  14. Hibernate:
  15. select
  16. classinfo0_.id as id1_1_0_,
  17. classinfo0_.no as no2_1_0_,
  18. classinfo0_.name as name3_1_0_
  19. from
  20. tb_class classinfo0_
  21. where
  22. classinfo0_.id=?
  23. Student [id=1, no=000001, name=学生1, sex=男, birthday=2015-01-27]
  24. ClassInfo [id=22, no=000022, name=班级22]
  25. 关闭数据库
    从控制台输出中,我们可以看到在调用session.get方法得到Student对象时Hibernate生成了两条SQL语句查询出了Student对象和与这个Student关联的Class对象。

3.建立一对多的单向关联关系

    我们也可以通过元素配置映射一对多的单向关联,但是一般情况下不推荐使用一对多的单向关联,更建议使用一对多的双向关联。使用一对多的单向关联需要使用one-to-many元素配置映射,具体配置如下:
  1. <hibernate-mapping package="model">
  2. <class name="Student" table="tb_student">
  3. <id name="id">
  4. <generator class="native"></generator>
  5. </id>
  6. <property name="no" column="no"/>
  7. <property name="name" column="name"/>
  8. <property name="sex" column="sex"/>
  9. <property name="birthday" column="birthday"/>
  10. </class>
  11. </hibernate-mapping>
  1. <hibernate-mapping package="model">
  2. <class name="ClassInfo" table="tb_class">
  3. <id name="id">
  4. <generator class="native"></generator>
  5. </id>
  6. <property name="no" column="no"/>
  7. <property name="name" column="name"/>
  8. <bag name="students">
  9. <key column="class_id"/>
  10. <one-to-many class="model.Student"/>
  11. </bag>
  12. </class>
  13. </hibernate-mapping>
    由于ClassInfo类的students属性类型是List<Student>属于List集合,所以使用对应的bag元素配置,其配置说明如下:
    1. bag name:设置需要映射的实体类属性名。
    2. key column:设置和实体类的属性对应的表的外键。注意:Hibernate默认此外键参照的是对应实体类的主键,在这里即是class_id参照ClassInfo实体类的id。
    3. one-to-many class:设置需要映射的实体类属性的类型。
    编写测试程序如下:
  1. public static void main(String[] args)
  2. {
  3. ClassInfo classInfo;
  4. Configuration cfg = new Configuration();
  5. cfg.configure();
  6. ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
  7. SessionFactory sf = cfg.buildSessionFactory(sr);
  8. System.out.println("连接数据库");
  9. Session session = sf.openSession();

  10. classInfo =(ClassInfo) session.get(ClassInfo.class, new Long(1));
  11. System.out.println(classInfo);
  12. System.out.println(classInfo.getStudents().size());
  13. System.out.println(classInfo.getStudents().get(0));

  14. session.close();
  15. System.out.println("关闭数据库");
  16. System.exit(0);
  17. }
    运行结果如下:
  1. 连接数据库
  2. Hibernate:
  3. select
  4. classinfo0_.id as id1_1_0_,
  5. classinfo0_.no as no2_1_0_,
  6. classinfo0_.name as name3_1_0_
  7. from
  8. tb_class classinfo0_
  9. where
  10. classinfo0_.id=?
  11. ClassInfo [id=1, no=000001, name=班级1]
  12. Hibernate:
  13. select
  14. students0_.class_id as class_id6_1_0_,
  15. students0_.id as id1_2_0_,
  16. students0_.id as id1_2_1_,
  17. students0_.no as no2_2_1_,
  18. students0_.name as name3_2_1_,
  19. students0_.sex as sex4_2_1_,
  20. students0_.birthday as birthday5_2_1_,
  21. students0_.class_id as class_id6_2_1_
  22. from
  23. tb_student students0_
  24. where
  25. students0_.class_id=?
  26. 35
  27. Student [id=24, no=000024, name=学生24, sex=女, birthday=2015-01-27]
  28. 关闭数据库
    根据输出结果可知当调用classInfo.getStudents().size()方法时,Hibernate会自动查询出ClassInfo对象关联的Student对象(第二个SQL)。从运行结果中看到Hibernate的两条SQL并不是连续执行的,这是由于Hibernate默认使用了懒加载,所以在程序访问ClassInfo类的students时Hibernate才会去数据库中取数据。

4.建立一对多的双向关联关系

(1)使用一对多双向关联
    综合上面两个例子,同时使用元素和元素配置如下:
  1. <hibernate-mapping package="model">
  2. <class name="Student" table="tb_student">
  3. <id name="id">
  4. <generator class="native"></generator>
  5. </id>
  6. <property name="no" column="no"/>
  7. <property name="name" column="name"/>
  8. <property name="sex" column="sex"/>
  9. <property name="birthday" column="birthday"/>
  10. <many-to-one name="classInfo" column="class_id" class="model.ClassInfo" lazy="false"/>
  11. </class>
  12. </hibernate-mapping>
  1. <hibernate-mapping package="model">
  2. <class name="ClassInfo" table="tb_class">
  3. <id name="id">
  4. <generator class="native"></generator>
  5. </id>
  6. <property name="no" column="no"/>
  7. <property name="name" column="name"/>
  8. <bag name="students" inverse="false" cascade="none" lazy="false">
  9. <key column="class_id"/>
  10. <one-to-many class="model.Student"/>
  11. </bag>
  12. </class>
  13. </hibernate-mapping>
    测试程序如下:
  1. public static void main(String[] args)
  2. {
  3. Student student;
  4. Configuration cfg = new Configuration();
  5. cfg.configure();
  6. ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
  7. SessionFactory sf = cfg.buildSessionFactory(sr);
  8. System.out.println("连接数据库");
  9. Session session = sf.openSession();
  10. student=(Student) session.get(Student.class, new Long(1));
  11. System.out.println(student);
  12. System.out.println(student.getClassInfo());
  13. System.out.println(student.getClassInfo().getStudents().size());
  14. session.close();
  15. System.out.println("关闭数据库");
  16. System.exit(0);
  17. }
    控制台输出如下:
  1. 连接数据库
  2. Hibernate:
  3. select
  4. student0_.id as id1_2_0_,
  5. student0_.no as no2_2_0_,
  6. student0_.name as name3_2_0_,
  7. student0_.sex as sex4_2_0_,
  8. student0_.birthday as birthday5_2_0_,
  9. student0_.class_id as class_id6_2_0_
  10. from
  11. tb_student student0_
  12. where
  13. student0_.id=?
  14. Hibernate:
  15. select
  16. classinfo0_.id as id1_1_0_,
  17. classinfo0_.no as no2_1_0_,
  18. classinfo0_.name as name3_1_0_
  19. from
  20. tb_class classinfo0_
  21. where
  22. classinfo0_.id=?
  23. Hibernate:
  24. select
  25. students0_.class_id as class_id6_1_0_,
  26. students0_.id as id1_2_0_,
  27. students0_.id as id1_2_1_,
  28. students0_.no as no2_2_1_,
  29. students0_.name as name3_2_1_,
  30. students0_.sex as sex4_2_1_,
  31. students0_.birthday as birthday5_2_1_,
  32. students0_.class_id as class_id6_2_1_
  33. from
  34. tb_student students0_
  35. where
  36. students0_.class_id=?
  37. Student [id=1, no=000001, name=学生1, sex=男, birthday=2015-01-27]
  38. ClassInfo [id=22, no=000022, name=班级22]
  39. 38
  40. 关闭数据库
    由于我在配置文件中禁用了懒加载(lazy="false"),所以调用session.get(Student.class, new Long(1))时Hibernate连续执行了3条SQL语句从数据库中取出所有关联的数据!
(2)bag元素的inverse属性详解
    由于ClassInfo类和Student类是双向关联,Hibernate默认会根据ClassInfo类或Student类维护其关联关系(即会执行相应的update语句),但是这会造成Hibernate执行不必要的SQL,对于同一个关联关系会维护两次,如下:
  1. public static void main(String[] args)
  2. {
  3. ClassInfo classInfoNew;
  4. ClassInfo classInfo;
  5. Student studentNew;
  6. Student student;
  7. Configuration cfg = new Configuration();
  8. cfg.configure();
  9. ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
  10. SessionFactory sf = cfg.buildSessionFactory(sr);
  11. System.out.println("连接数据库");
  12. Session session = sf.openSession();
  13. Transaction transaction = session.beginTransaction();
  14. try
  15. {
  16. classInfoNew = new ClassInfo();
  17. classInfoNew.setName("测试Class");
  18. classInfoNew.setNo("000");
  19. studentNew = new Student();
  20. studentNew.setName("测试Student");
  21. studentNew.setNo("000");
  22. studentNew.setSex("男");
  23. studentNew.setBirthday(new Date(1993, 6, 11));
  24. classInfoNew.getStudents().add(studentNew);
  25. studentNew.setClassInfo(classInfoNew);
  26. session.save(classInfoNew);//一定要先保存classInfo不然会报错,因为数据库约束了class_id为NOT NULL
  27. session.save(studentNew);
  28. student = (Student) session.get(Student.class, new Long(1));
  29. student.setClassInfo(classInfoNew);//执行update维护关系
  30. classInfoNew.getStudents().add(student);//执行update维护关系,update语句数受关联对象数影响,此处的update会有重复!
  31. transaction.commit();
  32. }
  33. catch (Exception e)
  34. {
  35. transaction.rollback();
  36. System.out.println("错误:" + e);
  37. }
  38. finally
  39. {
  40. session.close();
  41. System.out.println("关闭数据库");
  42. }
  43. System.exit(0);
  44. }
    运行结果如下,注意最后的三条update语句:
  1. 连接数据库
  2. Hibernate: insert into tb_class (no, name) values (?, ?)
  3. Hibernate: insert into tb_student (no, name, sex, birthday, class_id) values (?, ?, ?, ?, ?)
  4. Hibernate:
  5. ........ 省略若干获取关联对象的查询语句
  6. Hibernate: update tb_student set no=?, name=?, sex=?, birthday=?, class_id=? where id=?
  7. Hibernate: update tb_student set class_id=? where id=?
  8. Hibernate: update tb_student set class_id=? where id=?
  9. 关闭数据库
    重复执行多余的SQL语句会影响Java应用程序的性能,解决这一问题的办法是把bag元素的inverse属性设为true,该属性默认为false。inverse="true"表明在与的双向关联关系中,ClassInfo端的关联只是Student端关联的镜像,当Hibernate探测到对象ClassInfo和Student的属性都发生变化时,仅按照Student对象属性的变化更新数据库。
  1. <bag name="students" lazy="false" inverse="true">
  2.     <key column="class_id"/>
  3.     <one-to-many class="model.Student"/>
  4. </bag>
    设置后,再执行上面的程序,只会执行一条如下的SQL语句:
  1. Hibernate: update tb_student set no=?, name=?, sex=?, birthday=?, class_id=? where id=?
    根据以上实验,可以得出这样的结论:
    1. 在映射一对多的双向关联关系时,应该在“one”放把bag元素的inverse属性设置为true,这样可以减少不必要的SQL执行,提高应用程序的性能。
    2. 在建立两个对象的双向关联时,应该同时修改关联两端对象的相应属性:student.setClassInfo(classInfoNew); classInfoNew.getStudents().add(student);
(3)级联操作(cascade)​
    当Hibernate保存一个临时对象时,在默认情况下它不会自动保存所关联的其它临时对象,所以会抛出TransientObjectException异常,如果希望保存Student对象时自动级联保存ClassInfo对象,可以把cascade的属性设置成save-update,配置如下:
  1. <many-to-one name="classInfo" column="class_id" class="model.ClassInfo" lazy="false" cascade="save-update"/>
    当调用session.save(studentNew);时Hibernate会执行如下SQL:
  1. 连接数据库
  2. Hibernate: insert into tb_class (no, name) values (?, ?)
  3. Hibernate: insert into tb_student (no, name, sex, birthday, class_id) values (?, ?, ?, ?, ?)
  4. 关闭数据库
    cascade属性的默认值为none,当Hibernate删除一个持久化对象时,不会自动删除与它关联的其他持久化对象。如果希望Hibernate删除ClassInfo对象时,自动删除和ClassInfo关联的Student对象,可以把cascade属性设为delete,配置如下:
  1. <bag name="students" lazy="false" inverse="true" cascade="delete">
  2. <key column="class_id"/>
  3. <one-to-many class="model.Student" />
  4. </bag>
    当调用session.delete(classInfo);时,Hibernate会执行如下SQL:
  1. Hibernate: delete from tb_student where id=?
  2. Hibernate: delete from tb_class where id=?
​    如果希望Hibernate自动删除不再和ClassInfo对象关联的Student对象,可以把cascade属性设置成all-delete-orphan,“all-delete-orphan”包含了“all”和“delete-orphan”的行为,配置如下:
  1. <bag name="students" lazy="false" inverse="true" cascade="all-delete-orphan">
  2. <key column="class_id"/>
  3. <one-to-many class="model.Student" />
  4. </bag>

5.建立一对多的双向自身关联关系

    在实际的开发中包含一对多的关联关系的对象可能是同一个对象,例如某系统的区域信息表(tb_area),下面讲解如何映射一对多的自身关联,如下图:
                
    新建tb_area表的语句如下,外键约束可选:
  1. CREATE TABLE tb_area
  2. (
  3. id bigint NOT NULL auto_increment COMMENT 'ID',
  4. name varchar(50) NOT NULL COMMENT '地区名称',
  5. parent_id bigint COMMENT '所属区域ID',
  6. PRIMARY KEY (id)
  7. ) COMMENT = '区域信息表';
  8. -- 外键约束可续选
  9. ALTER TABLE tb_area ADD CONSTRAINT fk_tb_area_1 FOREIGN KEY (parent_id) REFERENCES tb_area (id);
    对应的实体类Area代码如下:
  1. package model;
  2. import java.util.Set;
  3. public class Area
  4. {
  5. private Long id;
  6. private String name;
  7. private Area parentArea;
  8. private Set<Area> childAreas = new HashSet<Area>();
  9. // 省略setter、getter、toString...
  10. }
    映射文件(Area.hbm.xml),由于Area对象childAreas属性使用的Set类型的集合,所以相应的使用set元素配置映射,关于Java集合类型的映射将会在后面的文章中讲到,本例的配置如下:
  1. <hibernate-mapping package="model">
  2. <class name="Area" table="tb_area">
  3. <id name="id">
  4. <generator class="native"></generator>
  5. </id>
  6. <property name="name" column="name"/>
  7. <many-to-one name="parentArea" column="parent_id" class="model.Area" cascade="save-update"/>
  8. <set name="childAreas" inverse="true">
  9. <key column="parent_id"/>
  10. <one-to-many class="model.Area"/>
  11. </set>
  12. </class>
  13. </hibernate-mapping>
    测试代码以及控制台打印结果如下:
  1. public static void main(String[] args)
  2. {
  3. Configuration cfg = new Configuration();
  4. cfg.configure();
  5. ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
  6. SessionFactory sf = cfg.buildSessionFactory(sr);
  7. System.out.println("连接数据库");
  8. Session session = sf.openSession();
  9. Transaction transaction = session.beginTransaction();
  10. try
  11. {
  12. Area area1=new Area();
  13. Area area2=new Area();
  14. Area area3=new Area();
  15. Area area4=new Area();
  16. Area area5=new Area();
  17. area1.setName("中国");
  18. area2.setName("湖北省");
  19. area3.setName("湖南省");
  20. area4.setName("武汉市");
  21. area5.setName("仙桃市");
  22. area2.setParentArea(area1);
  23. area3.setParentArea(area1);
  24. area4.setParentArea(area2);
  25. area5.setParentArea(area2);
  26. session.save(area3);
  27. session.save(area4);
  28. session.save(area5);
  29. transaction.commit();
  30. }
  31. catch (Exception e)
  32. {
  33. transaction.rollback();
  34. System.out.println("错误:" + e);
  35. }
  36. finally
  37. {
  38. session.close();
  39. System.out.println("关闭数据库");
  40. }
  41. System.exit(0);
  42. }
  1. 连接数据库
  2. Hibernate: insert into tb_area (name, parent_id) values (?, ?)
  3. Hibernate: insert into tb_area (name, parent_id) values (?, ?)
  4. Hibernate: insert into tb_area (name, parent_id) values (?, ?)
  5. Hibernate: insert into tb_area (name, parent_id) values (?, ?)
  6. Hibernate: insert into tb_area (name, parent_id) values (?, ?)
  7. 关闭数据库
    由于配置了级联保存和更新(cascade="save-update"和inverse="true"),所以保存了5条数据。

6.改进持久化类

    如果要建立地区中国与湖北省的关系,必须要调用下面的代码:
  1. area1.setName("中国");
  2. area2.setName("湖北省");
  3. area2.setParentArea(area1);
  4. area1.getChildAreas().add(area2);
    为了简化管理对象之间的关联关系的编程代码,可以在Area类中增加addChildArea方法,代码如下:
  1. public Area addChildArea(Area area)
  2. {
  3. if (area != null)
  4. {
  5. if (this.childAreas == null)
  6. {
  7. this.childAreas = new HashSet<Area>();
  8. }
  9. //删除原有的关系
  10. if (area.getParentArea() != null)
  11. {
  12. area.getParentArea().getChildAreas().remove(area);
  13. }
  14. //设置当前关系
  15. this.childAreas.add(area);
  16. area.setParentArea(this);
  17. }
  18. return this;
  19. }
    使用此方法可以很方便的设置关联关系,如下代码:
  1. area1.setName("中国");
  2. area2.setName("湖北省");
  3. area3.setName("湖南省");
  4. area1.addChildArea(area2).addChildArea(area3);

7.一对多、多对一相关配置详细说明

(1)many-to-one节点配置说明
  1. <many-to-one name="PropertyName"
  2. access="field|property"
  3. column="TableColumn"
  4. class="ClassName"
  5. property-ref="PropertyNameFromAssociatedClass"
  6. foreign-key="foreign-key"
  7. formula="arbitrary SQL expression"
  8. update="true|false"
  9. insert="true|false"
  10. not-null="true|false"
  11. unique="true|false"
  12. unique-key="unique-key"
  13. index="index_name"
  14. not-found="exception|ignore"
  15. outer-join="true|false"
  16. fetch="join|select"
  17. lazy="true|false"
  18. cascade="all|none|save-update|delete"
  19. optimistic-lock="true|false"
  20. embed-xml="true|false"
  21. entity-name="EntityName"
  22. node="element-name"/>
    如上展示了many-to-one节点常用的配置,是面对其配置进行详细的说明:
  1. name:实体类属性名。
  2. access:默认的实体类属性访问模式,取值为property表示访问getter、setter方法间接访问实体类字段,取值为field表示直接访问实体类字段(类成员变量)。
  3. column:对应的数据库字段名,此处的字段是外键字段。
  4. class:关联的类的名字,默认是通过反射得到属性类型。
  5. property-ref:指定关联类的一个属性,这个属性将会和本外键相对应。如果没有指定,会使用对方关联类的主键。
  6. foreign-key:关联的数据库外键名。
  7. formula:一个SQL表达式,定义了这个计算属性的值,计算属性没有和它对应的数据库字段。
  8. update:在update时是否含有此字段。
  9. insert:在insert时是否含有此字段。
  10. not-null:字段能否为空。
  11. unique:字段是否唯一。
  12. unique-key:为此字段创建唯一约束,属性值即为数据库唯一约束名,只影响自动生成的schema脚本。
  13. index:为此字段创建索引,属性值即为数据库索引名,只影响自动生成的schema脚本。
  14. not-found:指定外键引用的数据不存在时如何处理,ignore会将数据不存在作为关联到一个空对象(null)处理,默认为exception。
  15. outer-join:设置Hibernate是否使用外连接获取关联的数据,设置成true可以减少SQL语句的条数。
  16. fetch:参数指定了关联对象抓取的方式是select查询还是join查询,默认为select。fetch="join"等同于outer-join="true",fetch="select"等同于outer-join="false"。
  17. lazy:是否采用延迟加载策略。
  18. cascade:指明哪些操作会从父对象级联到关联的对象。
  19. optimistic-lock:指定这个属性在做更新时是否需要获得乐观锁定,默认为true。
  20. embed-xml:如果embed-xml="true",则对应于被关联实体或值类型的集合的XML树将直接嵌入拥有这些关联的实体的XML树中,默认值为true。
  21. entity-name:Hibernate3新增特性,用于动态模型(Dynamic Model)支持。Hibernate3允许一个类进行多次映射(前提是映射到不同的表)。
  22. node:配置说明。
(2)bag节点配置说明
  1. <bag name="EntityClassName"
  2. access="field|property|ClassName"
  3. collection-type="collection-type"
  4. schema="schema"
  5. catalog="catalog"
  6. check="arbitrary sql check condition"
  7. table="TableName"
  8. subselect="SQL expression"
  9. where="arbitrary sql where condition"
  10. optimistic-lock="false|true"
  11. inverse="false|true"
  12. fetch="join|select"
  13. batch-size="5"
  14. cascade="all|none|save-update|delete"
  15. lazy="false|true"
  16. mutable="false|true"
  17. outer-join="false|true"
  18. order-by="arbitrary sql order by condition"
  19. embed-xml="false|true"
  20. persister="PersisterClass"
  21. node="element-name"/>
    如上展示了bag节点常用的配置,是面对其配置进行详细的说明:
  1. name:实体类属性名。
  2. access:默认的实体类属性访问模式,取值为property表示访问getter、setter方法间接访问实体类字段,取值为field表示直接访问实体类字段(类成员变量)。
  3. collection-type:
  4. schema:数据库schema。
  5. catalog:数据库catalog。
  6. check:这是一个SQL表达式,用于为自动生成的schema添加多行约束检查。
  7. table:此集合里的实体类对应的数据库表名。
  8. subselect:一个SQL子查询,它将一个不可变并且只读的实体映射到一个数据库的子查询。
  9. where:一个SQL查询的where条件,获取这个关联类的对象时会一直增加这个条件。
  10. optimistic-lock:指定这个属性在做更新时是否需要获得乐观锁定,默认为true。
  11. inverse:当设置inverse="true"时,Hibernate将根此集合里的实体类类型的关联属性维护关联关系,默认值false。
  12. fetch:参数指定了关联对象抓取的方式是select查询还是join查询,默认为select。fetch="join"等同于outer-join="true",fetch="select"等同于outer-join="false"。
  13. batch-size:用于设置批次操作的SQL语句的数量,默认为1。
  14. cascade:指明哪些操作会从父对象级联到关联的对象。
  15. lazy:是否采用延迟加载策略。
  16. mutable:此集合里的实体类是否会发生改变,如果类实例对应的数据库表记录不会发生更新,可将其设为false,适用于单纯的Insert操作不使用update操作。
  17. outer-join:设置Hibernate是否使用外连接获取关联的数据,设置成true可以减少SQL语句的条数。
  18. order-by:一个SQL查询的order by条件,获取这个关联类的对象时会一直增加这个条件。
  19. embed-xml:如果embed-xml="true",则对应于被关联实体或值类型的集合的XML树将直接嵌入拥有这些关联的实体的XML树中,默认值为true。
  20. persister:指定持久化实现类,通过指定持久化类,我们可以实现自定义的持久化方法。持久化类为ClassPersister接口的实现。
  21. node:配置说明。
(3)one-to-many节点配置说明
  1. <one-to-many class="ClassName"
  2. not-found="exception|ignore"
  3. embed-xml="true|false"
  4. entity-name="EntityName"
  5. node="element-name" />
    如上展示了one-to-many节点常用的配置,是面对其配置进行详细的说明:
  1. class:关联的类的名字,默认是通过反射得到属性类型。
  2. not-found:指定外键引用的数据不存在时如何处理,ignore会将数据不存在作为关联到一个空对象(null)处理,默认为exception。
  3. embed-xml:如果embed-xml="true",则对应于被关联实体或值类型的集合的XML树将直接嵌入拥有这些关联的实体的XML树中,默认值为true。
  4. entity-name:Hibernate3新增特性,用于动态模型(Dynamic Model)支持。Hibernate3允许一个类进行多次映射(前提是映射到不同的表)。
  5. node:配置说明。
-------------------------------------------------------------------------------------------------------------------------------

03.Hibernate一对多关联的更多相关文章

  1. hibernate一对多关联映射

    一对多关联映射 映射原理 一对多关联映射和多对一关联映射的映射原理是一致的,都是在多的一端加入一个外键,指向一的一端.关联关系都是由多端维护,只是在写映射时发生了变化. 多对一和一对多的区别 多对一和 ...

  2. Hibernate一对多关联映射的配置及其级联删除问题

    首先举一个简单的一对多双向关联的配置: 一的一端:QuestionType类 package com.exam.entity; import java.util.Set; public class Q ...

  3. 转Hibernate 一对多关联的CRUD__@ManyToOne(cascade=(CascadeType.ALL))

    一:Group和Users两个类 假定一个组里有n多用户,但是一个用户只对应一个用户组. 1.所以Group对于Users是“一对多”的关联关系@OneToMany Users对于Group是“多对一 ...

  4. Hibernate一对多关联

    一对多双向关联关系:(Dept/Emp的案例) 既可以根据在查找部门时根据部门去找该部门下的所有员工,又能在检索员工时获取某个员工所属的部门. 步骤如下: 1.构建实体类(部门实体类加set员工集合) ...

  5. hibernate 一对多关联

    package com.bjsxt.hibernate; import java.util.HashSet; import java.util.Set; import javax.persistenc ...

  6. hibernate 一对多双向关联 详解

    一.解析: 1.  一对多双向关联也就是说,在加载班级时,能够知道这个班级所有的学生. 同时,在加载学生时,也能够知道这个学生所在的班级. 2.我们知道,一对多关联映射和多对一关联映射是一样的,都是在 ...

  7. Hibernate一对多单向关联和双向关联映射方法及其优缺点 (待续)

    一对多关联映射和多对一关联映射实现的基本原理都是一样的,既是在多的一端加入一个外键指向一的一端外键,而主要的区别就是维护端不同.它们的区别在于维护的关系不同: 一对多关联映射是指在加载一的一端数据的同 ...

  8. (Hibernate进阶)Hibernate映射——一对多关联映射(七)

    一对多关联映射 映射原理 一对多关联映射和多对一关联映射的映射原理是一致的,都是在多的一端加入一个外键,指向一的一端.关联关系都是由多端维护,只是在写映射时发生了变化. 多对一和一对多的区别 多对一和 ...

  9. 【SSH系列】Hibernate映射 -- 一对多关联映射

        映射原理       一对多关联映射和多对一关联映射的映射原理是一样一样的,所以说嘛,知识都是相通的,一通百通,为什么说一对多关联映射和多对一关联映射是一样的呢?因为她们都是在多的一端加入一个 ...

随机推荐

  1. 软件工程 speedsnail 第二次冲刺2

    20150519 完成任务:划线第二天,能画出一条直黄线: 遇到问题: 问题1 划线的代码和移动的setcontentview冲突,无法同时显示 解决1 没有解决 明日任务: 线与移动共存

  2. windows下如何修改远程登录端口

    windows下如何修改远程登录端口 windows远程桌面默认端口为3389,修改 方法如下:在"开始>运行"中输入"regedit" 点击“确定”,打 ...

  3. AddToDate

    AddToDate is a PeopleCode built-in function for manipulating a date in PeopleCode. You can use it to ...

  4. Check for Data Duplicates on a Grid

    Here is a piece of code to prevent duplicate data on a specific field on a page grid. You can of cou ...

  5. C#winform导出数据到Excel的类

    /// <summary> /// 构造函数 /// </summary> public ExportData() { } /// <summary> /// 保存 ...

  6. [leetcode]_Climbing Stairs

    我敢保证这道题是在今早蹲厕所的时候突然冒出的解法.第一次接触DP题,我好伟大啊啊啊~ 题目:一个N阶的梯子,一次能够走1步或者2步,问有多少种走法. 解法:原始DP问题. 思路: 1.if N == ...

  7. 状态可以通过动画切换的按钮--第三方开源--TickPlusDrawable

    Android tickplusdrawable(TickPlusDrawable)在github上的项目主页是:https://github.com/flavienlaurent/tickplusd ...

  8. web app 开发

    去除手机浏览器标签默认高亮边框 -webkit-tap-highlight-color 属性 属性描述:这个属性可以指设置透明度.如果未设置透明度,iOS上的Safari会给予颜色一个默认的透明度.把 ...

  9. C语言中的堆与栈20160604

    首先声明这里说的是C语言中的堆与栈,并不是数据结构中的!一.前言介绍:C语言程序经过编译连接后形成编译.连接后形成的二进制映像文件是静态区域由代码段和数据段(由二部分部分组成:只读数据 段,未初始化数 ...

  10. 第十三章 调试及安全性(In .net4.5) 之 验证程序输入

    1. 概述 本章介绍验证程序输入的重要性以及各种验证方法:Parse.TryParse.Convert.正则表达式.JavaScriptSerializer.XML Schemas. 2. 主要内容 ...