zoukankan      html  css  js  c++  java
  • HIbernate学习笔记(七) hibernate中的集合映射和继承映射

    九、       集合映射

    1、 Set

    2、 List

    a)        @OrderBy

    注意:List与Set注解是一样的,就是把Set更改为List就可以了

      private List<User>users = new ArrayList<User>();

      @OneToMany(mappedBy="group",

              cascade={CascadeType.ALL}

              )

      @OrderBy("name ASC")//使用@OrderBy注解List中使用哪个字段进行排序,可以组合排序,中间使用逗号分开

      public List<User>getUsers() {  return users;}

      public voidsetUsers(List<User> users) {this.users = users;}

    3、 Map

    a)        @Mapkey

    注解:关联模型中并没有变化,只是注解发生了变化,而这个变化是给hibernate看的

    Map在映射时,因为Key是唯一的,所以一般可以使用主键表示,然后在映射时使用@MapKey来注解使用哪个字段为key,如下:

    private Map<Integer,User> users = new HashMap<Integer, User>();

    @OneToMany(mappedBy="group", cascade=CascadeType.ALL)

    @MapKey(name="id")//注解使用哪个字段为key

    public Map<Integer,User> getUsers() {  return users;}

    public voidsetUsers(Map<Integer, User> users) {this.users = users;}

                       数据加载:

         Session s = sessionFactory.getCurrentSession();

         s.beginTransaction();

         Group g =(Group)s.load(Group.class, 1);

         for(Map.Entry<Integer,User> entry : g.getUsers().entrySet()) {

             System.out.println(entry.getValue().getName());

         }

         s.getTransaction().commit();

    十、        继承关联映射

    继承映射:就是把类的继承关系映射到数据库里(首先正确的存储,再正确的加载数据)

    (一) 继承关联映射的分类:

    Ø        单表继承:每棵类继承树使用一个表(table per class hierarchy)

    Ø        具体表继承:每个子类一个表(table per subclass)

    Ø        类表继承:每个具体类一个表(table per concrete class)(有一些限制)

    Ø        实例环境:动物Animal有三个基本属性,然后有一个Pig继承了它并扩展了一个属性,还有一个Brid也继承了并且扩展了一个属性

    (二) 对象模型:

    (三) 单表继承SINGLE_TABLE

    每棵类继承树使用一个表

    把所有的属性都要存储表中,目前至少需要5个字段,另外需要加入一个标识字段(表示哪个具体的子类)

    t_animal

    Id

    Name

    Sex

    Weight

    Height

    Type

    1

    猪猪

    true

    100

    P

    2

    鸟鸟

    false

    50

    B

    其中:

               ①、id:表主键

               ②、name:动物的姓名,所有的动物都有

               ③、sex:动物的性别,所有的动物都有

               ④、weight:猪(Pig)的重量,只有猪才有,所以鸟鸟就没有重量数据

               ⑤、height:鸟(height)的调试,只有鸟才有,所以猪猪就没有高度数据

               ⑥、type:表示动物的类型;P表示猪;B表示鸟

    1、 实体类

    Animal实体类:

    public class Animal {

      private int id;

      private String name;   

      private boolean sex;

      public int getId() {return id;  }

      public void setId(int id) { this.id = id;}

      public String getName() {return name;}

      public void setName(Stringname) {this.name = name;}

      public boolean isSex() {return sex;}

      public void setSex(boolean sex) {this.sex = sex;}  

    }

    Pig实体类:

    public class Pig extends Animal {

      private int weight;

      public int getWeight() {return weight;}

      public void setWeight(int weight) {this.weight = weight;}

    }

    Bird实体类:

    public class Bird extends Animal {

      private int height;

      public int getHeight() {return height;}

      public void setHeight(int height) {this.height = height;}  

    }

    2、 xml方式:映射

      <class name="Animal" table="t_animal"lazy="false">

          <id name="id">

              <generator class="native"/>

          </id>

          <discriminator column="type" type="string"/>

          <property name="name"/>

          <property name="sex"/>

          <subclass name="Pig" discriminator-value="P">

              <property name="weight"/>

          </subclass>

          <subclass name="Bird" discriminator-value="B">

              <property name="height"/>

          </subclass>

      </class>

     

    1、理解如何映射

          因为类继承树肯定是对应多个类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪个类的。

      这种机制就是,在表中添加一个字段,用这个字段的值来进行区分。用hibernate实现这种策略的时候,有如下步骤:

      父类用普通的<class>标签定义

      在父类中定义一个discriminator,即指定这个区分的字段的名称和类型

      如:<discriminator column=”XXX” type=”string”/>

      子类使用<subclass>标签定义,在定义subclass的时候,需要注意如下几点:

      Subclass标签的name属性是子类的全路径名

      在Subclass标签中,用discriminator-value属性来标明本子类的discriminator字段(用来区分不同类的字段)

      的值Subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标

      签平行。 当subclass标签的定义与class标签平行的时候,需要在subclass标签中,添加extends属性,里面的值

      是父类的全路径名称。子类的其它属性,像普通类一样,定义在subclass标签的内部。

     

    2、理解如何存储

      存储的时候hibernate会自动将鉴别字段值插入到数据库中,在加载数据的时候,hibernate能根据这个鉴别值

      正确的加载对象

     

    多态查询:在hibernate加载数据的时候能鉴别出正真的类型(instanceOf)

     

    get支持多态查询

    load只有在lazy=false,才支持多态查询

    hql支持多态查询

    3、 annotation注解

    父类中注解如下:

     使用@Inheritance注解为继承映射,再使用strategy属性来指定继承映射的方式

     strategy有三个值:InheritanceType.SINGLE_TABLE           单表继承

                      InheritanceType.TABLE_PER_CLASS       类表继承

                      InheritanceType.JOINED            具体表继承

     再使用@DiscriminatorColumn注意标识字段的字段名,及字段类型

     在类中使用@DiscriminatorValue来注解标识字段的值

    @Entity

    @Inheritance(strategy=InheritanceType.SINGLE_TABLE)

    @DiscriminatorColumn(

    name="discriminator",

    discriminatorType=DiscriminatorType.STRING)

    @DiscriminatorValue("person")

    public class Person {private int id;private String name;

     

      @Id

      @GeneratedValue

    public int getId() {return id;}

    继承类中注解如下:

        只需要使用@DiscriminatorValue来注解标识字段的值

     

    4、 导出后生成SQL语句:

    create table t_animal (id integer not null auto_increment, typevarchar(255) not null, name varchar(255), sex bit, weight integer, heightinteger, primary key (id))

    5、 数据库中表结构:


    6、 单表继承数据存储:

    session = HibernateUtils.getSession();

                tx =session.beginTransaction();

       

                Pig pig = new Pig();

                pig.setName("猪猪");

                pig.setSex(true);

                pig.setWeight(100);

                session.save(pig);

               

                Bird bird = new Bird();

                bird.setName("鸟鸟");

                bird.setSex(false);

                bird.setHeight(50);

                session.save(bird);

               

                tx.commit();

    存储执行输出SQL语句:

    Hibernate: insert into t_animal (name, sex, weight, type) values (?, ?, ?,'P')//自动确定无height字段,并且设置标识符为P

    Hibernate: insert into t_animal (name, sex, height, type) values (?, ?, ?,'B') //自动确定无weight字段,并且设置标识符为B

    解释:hibernate会根据单表继承映射文件的配置内容,自动在插入数据时哪个子类需要插入哪些字段,并且自动插入标识符字符值(在映射文件中配置了)

    7、 单表继承映射数据加载(指定加载子类):

        session =HibernateUtils.getSession();

        tx =session.beginTransaction();

               

        Pig pig =(Pig)session.load(Pig.class, 1);

        System.out.println("pig.name=" + pig.getName());

        System.out.println("pig.weight=" + pig.getWeight());

               

        Bird bird =(Bird)session.load(Bird.class, 2);

        System.out.println("bird.name" + bird.getName());

        System.out.println("bird.height=" + bird.getHeight());

               

        tx.commit();

    8、 加载执行输出SQL语句:

    Hibernate: select pig0_.id as id0_0_, pig0_.name as name0_0_, pig0_.sex assex0_0_, pig0_.weight as weight0_0_ from t_animal pig0_ where pig0_.id=? and pig0_.type='P'

    //hibernate会根据映射文件自动确定哪些字段(虽然表中有height,但hibernate并不会加载)属于这个子类,并且确定标识符为B(已经在配置文件中设置了)

    pig.name=猪猪

    pig.weight=100

    Hibernate: select bird0_.id as id0_0_, bird0_.name as name0_0_, bird0_.sexas sex0_0_, bird0_.height as height0_0_ from t_animal bird0_ where bird0_.id=?and bird0_.type='B'

    //hibernate会根据映射文件自动确定哪些字段虽然表中有weight,但hibernate并不会加载属于这个子类,并且确定标识符为B(已经在配置文件中设置了)

    bird.name=鸟鸟

    bird.height=50

    9、 单表继承映射数据加载(指定加载父类):

    session = HibernateUtils.getSession();

                tx =session.beginTransaction();

               

                //不会发出SQL,返回一个代理类

                Animal animal =(Animal)session.load(Animal.class, 1);

                //发出SQL语句,并且加载所有字段的数据(因为使用父类加载对象数据)

                System.out.println("animal.name=" + animal.getName());

                System.out.println("animal.sex=" + animal.isSex());

               

                tx.commit();

    加载执行生成SQL语句:

    Hibernate: select animal0_.id as id0_0_, animal0_.name as name0_0_,animal0_.sex as sex0_0_, animal0_.weight asweight0_0_, animal0_.height as height0_0_, animal0_.type as type0_0_ from t_animal animal0_ where animal0_.id=?

    //注:因为使用父类加载数据,所以hibernate会将所有字段(height、weight、type)的数据全部加载,并且条件中没有识别字段type(也就不区分什么子类,把所有子类全部加载上来。)

    10、 单表继承映射数据加载(指定加载父类,看能否鉴别真实对象):

                session = HibernateUtils.getSession();

                tx =session.beginTransaction();

               

                //不会发出SQL语句(load默认支持延迟加载(lazy)),返回一个animal的代理对象(此代理类是继承Animal生成的,也就是说是Animal一个子类)

                Animal animal =(Animal)session.load(Animal.class, 1);

               

                //因为在上面返回的是一个代理类(父类的一个子类),所以animal不是Pig

                //通过instanceof是反应不出正直的对象类型的,因此load在默认情况下是不支持多态查询的。

                if (animal instanceof Pig) {

                    System.out.println("是猪");

                } else {

                    System.out.println("不是猪");//这就是结果

                }

                System.out.println("animal.name=" + animal.getName());

                System.out.println("animal.sex=" + animal.isSex());

               

                tx.commit();

    11、 多态查询:

    在hibernate加载数据的时候能鉴别出正直的类型(通过instanceof)

    get支持多态查询;load只有在lazy=false,才支持多态查询;HQL支持多态查询

    12、 采用load,通过Animal查询,将<class>标签上的lazy设置为false

    session = HibernateUtils.getSession();

                tx = session.beginTransaction();

               

                //会发出SQL语句,因为设置lazy为false,不支持延迟加载

                Animal animal =(Animal)session.load(Animal.class, 1);

                //可以正确的判断出Pig的类型,因为lazy=false,返回具体的Pid类型

                //此时load支持多态查询

                if (animal instanceof Pig) {

                    System.out.println("是猪");//结果

                } else {

                    System.out.println("不是猪");

                }

                System.out.println("animal.name=" + animal.getName());

                System.out.println("animal.sex=" + animal.isSex());

               

                tx.commit();

    13、 采用get,通过Animal查询,可以判断出正直的类型

                session = HibernateUtils.getSession();

                tx = session.beginTransaction();

               

                //会发出SQL语句,因为get不支持延迟加载,返回的是正直的类型,

                Animal animal =(Animal)session.load(Animal.class, 1);

     

                //可以判断出正直的类型

                //get是支持多态查询

                if (animal instanceof Pig) {

                    System.out.println("是猪");//结果

                } else {

                    System.out.println("不是猪");

                }

                System.out.println("animal.name=" + animal.getName());

                System.out.println("animal.sex=" + animal.isSex());

               

                tx.commit();

    14、 采用HQL查询,HQL是否支持多态查询

    List animalList = session.createQuery("from Animal").list();

                for (Iteratoriter = animalList.iterator(); iter.hasNext();) {

                    Animal a = (Animal)iter.next();

                    //能够正确鉴别出正直的类型,HQL是支持多态查询的。

                    if (a instanceof Pig) {

                        System.out.println("是Pig");

                    } else if (a instanceof Bird) {

                        System.out.println("是Bird");

                    }

                }

    15、 通过HQL查询表中所有的实体对象

    * HQL语句:session.createQuery("fromjava.lang.Object").list();

        * 因为所有对象都是继承Object类

    List list = session.createQuery("from java.lang.Object").list();

                for (Iteratoriter = list.iterator(); iter.hasNext();){

                    Object o =iter.next();

                    if (o instanceof Pig) {

                        System.out.println("是Pig");

                    } else {

                        System.out.println("是Bird");

                    }

                }

    (四) 具体表继承JOINED

    每个类映射成一个表(table per subclass)

    对象模型不用变化,存储模型需要变化


    1、 关系模型:

    每个类映射成一个表(table per subclass)

    注:因为需要每个类都映射成一张表,所以Animal也映射成一张表(t_animal),表中字段为实体类属性

    而pig子类也需要映射成一张表(t_pid),但为了与父类联系需要加入一个外键(pidid)指向父类映射成的表(t_animal),字段为子类的扩展属性。Bird子类同样也映射成一张表(t_bird),也加入一个外键(birdid)指向父类映射成的表(t_animal),字段为子类的扩展属性。

    2、 xml方式(每个类映射成一个表):

        <class name="com.wjt276.hibernate.Animal" table="t_animal">

            <id name="id"column="id"><!-- 映射主键 -->

                <generator class="native"/>

            </id>

            <property name="name"/><!-- 映射普通属性 -->

            <property name="sex"/>

            <!--<joined-subclass>标签:继承映射 每个类映射成一个表 -->

            <joined-subclass name="com.wjt276.hibernate.Pig" table="t_pig">

    <!-- <key>标签:会在相应的表(当前映射的表)里,加入一个外键 , 参照指向当前类的父类(当前Class标签对象的表(t_animal))-->

                <key column="pigid"/>

                <property name="weight"/>

            </joined-subclass>

            <joined-subclass name="com.wjt276.hibernate.Bird" table="t_bird">

                <key column="birdid"/>

                <property name="height"/>

            </joined-subclass>

        </class>

    1、理解如何映射

            这种策略是使用joined-subclass标签来定义子类的。父类、子类,每个类都对应一张数据库表。

        在父类对应的数据库表中,实际上会存储所有的记录,包括父类和子类的记录;在子类对应的数据库表中,

        这个表只定义了子类中所特有的属性映射的字段。子类与父类,通过相同的主键值来关联。实现这种策略的时候,

        有如下步骤:

        父类用普通的<class>标签定义即可

        父类不再需要定义discriminator字段

        子类用<joined-subclass>标签定义,在定义joined-subclass的时候,需要注意如下几点:

        Joined-subclass标签的name属性是子类的全路径名

        Joined-subclass标签需要包含一个key标签,这个标签指定了子类和父类之间是通过哪个字段来关联的。

        如:<key column=”PARENT_KEY_ID”/>,这里的column,实际上就是父类的主键对应的映射字段名称。

        Joined-subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),

        也可以与class标签平行。 当Joined-subclass标签的定义与class标签平行的时候,需要在Joined-subclass

        标签中,添加extends属性,里面的值是父类的全路径名称。子类的其它属性,像普通类一样,定义在joined-subclass标签的内部。

    3、 annotation注解

    因为,子类生成的表需要引用父类生成的表,所以只需要在父类设置具体表继承映射就可以了,其它子类只需要使用@Entity注解就可以了

    @Entity

    @Inheritance(strategy=InheritanceType.JOINED)

     

    public class Person {

        private int id;

        private String name;

        @Id

        @GeneratedValue

        public int getId() {return id;}

    4、 导出输出SQL语句:

    create table t_animal (id integer notnull auto_increment, name varchar(255), sex bit, primary key (id))

    create table t_bird (birdid integernot null, height integer, primary key (birdid))

    create table t_pig (pigid integer notnull, weight integer, primary key (pigid))

    altertable t_bird add index FKCB5B05A4A554009D(birdid), add constraint FKCB5B05A4A554009D foreign key (birdid) referencest_animal (id)

    alter table t_pig add index FK68F8743FE77AC32 (pigid), add constraint FK68F8743FE77AC32 foreign key (pigid) references t_animal (id)

    //共生成三个表,并在子类表中各有一个外键参照指向父类表

     

    数据的存储,不需要其它的任务变化,直接使用单表继承存储就可以了,加载也是一样。

    具体表继承效率没有单表继承高,但是单表继承会出现多余的庸于字段,具体表层次分明

     

    (五) 类表继承TABLE_PER_CLASS

    每个具体类映射成一个表(table per concreteclass)(有一些限制)

     

    对象模型不用变化,存储模型需要变化


    1、 关系模型:

    每个具体类(Pig、Brid)映射成一个表(table per concrete class)(有一些限制)

    t_pig

    Id

    Name

    Sex

    Weight

    1

    猪猪

    True

    100

    t_bird

    Id

    Name

    Sex

    Height

    2

    鸟鸟

    False

    50

    2、 xml方式:映射文件:

        <class name="com.wjt276.hibernate.Animal" table="t_animal">

            <id name="id"column="id"><!-- 映射主键 -->

                <generator class="assigned"/><!-- 每个具体类映射一个表主键生成策略不可使用native -->       </id>   

            <property name="name"/><!-- 映射普通属性 -->

            <property name="sex"/>

            <!--使用<union-subclass>标签来映射"每个具体类映射成一张表"的映射关系

                ,实现上上面的表t_animal虽然映射到数据库中,但它没有任何作用。      -->

            <union-subclass name="com.wjt276.hibernate.Pig" table="t_pig">

                <property name="weight"/>

            </union-subclass>

            <union-subclass name="com.wjt276.hibernate.Bird" table="t_bird">

                <property name="height"/>

            </union-subclass>

        </class>

    理解如何映射

        这种策略是使用union-subclass标签来定义子类的。每个子类对应一张表,而且这个表的信息是完备的,

        即包含了所有从父类继承下来的属性映射的字段(这就是它跟joined-subclass的不同之处,

        joined-subclass定义的子类的表,只包含子类特有属性映射的字段)。实现这种策略的时候,有如下步骤:

        父类用普通<class>标签定义即可

        子类用<union-subclass>标签定义,在定义union-subclass的时候,需要注意如下几点:

        Union-subclass标签不再需要包含key标签(与joined-subclass不同)

        Union-subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),

        也可以与class标签平行。 当Union-subclass标签的定义与class标签平行的时候,需要在Union-subclass

        标签中,添加extends属性,里面的值是父类的全路径名称。子类的其它属性,像普通类一样,

        定义在Union-subclass标签的内部。这个时候,虽然在union-subclass里面定义的只有子类的属性,

        但是因为它继承了父类,所以,不需要定义其它的属性,在映射到数据库表的时候,依然包含了父类的所

        有属性的映射字段。

        注意:在保存对象的时候id是不能重复的(不能使用自增生成主键)

    3、 annotation注解

    只需要对父类进行注解就可以了,

    因为子类表的ID是不可以重复,所以一般的主键生成策略已经不适应了,只有表主键生成策略。

    首先使用@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)来注解继承映射,并且使用具体表继承方式,使用@TableGenerator来申明一个表主键生成策略

    再在主键上@GeneratedValue(generator="t_gen", strategy=GenerationType.TABLE)来注解生成策略为表生成策略,并且指定表生成策略的名称

    继承类只需要使用@Entity进行注解就可以了

    @Entity

    @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)

    @TableGenerator(

          name="t_gen",

          table="t_gen_table",

          pkColumnName="t_pk",

          valueColumnName="t_value",

          pkColumnValue="person_pk",

          initialValue=1,

          allocationSize=1

          )

    public class Person {

    private int id;

    private String name;

     

      @Id

      @GeneratedValue(generator="t_gen", strategy=GenerationType.TABLE)

      public int getId() {return id;}

    4、 导出输出SQL语句:

    create table t_animal (id integer not null, name varchar(255), sex bit, primary key (id))

    create table t_bird (id integer not null, name varchar(255), sex bit, height integer, primary key(id))

    create table t_pig (id integer not null, name varchar(255), sex bit, weight integer, primary key(id))

    注:表t_animal、 t_bird、t_pig并不是自增的,是因为bird、pig都是animal类,也就是说animal不可以有相同的ID号(Bird、Pig是类型,只是存储的位置不同而以)

    5、 数据库表结构如下:


    注:如果不想t_animal存在(因为它没有实际的作用),可以设置<class>标签中的abstract="true"(抽象表),这样在导出至数据库时,就不会生成t_animal表了。

    <class name="com.wjt276.hibernate.Animal" table="t_animal" abstract="true">

            <id name="id"column="id"><!-- 映射主键 -->

    …………

    (六) 三种继承关联映射的区别:

    1、  第一种:它把所有的数据都存入一个表中,优点:效率好(操作的就是一个表);缺点:存在庸于字段,如果将庸于字段设置为非空,则就无法存入数据;

    2、  第二种:层次分明,缺点:效率不好(表间存在关联表)

    3、  第三种:主键字段不可以设置为自增主键生成策略。

    一般使用第一种

  • 相关阅读:
    bzoj3505 数三角形 组合计数
    cogs2057 殉国 扩展欧几里得
    cogs333 荒岛野人 扩展欧几里得
    bzoj1123 BLO tarjan求点双连通分量
    poj3352 road construction tarjan求双连通分量
    cogs1804 联合权值 dp
    cogs2478 简单的最近公共祖先 树形dp
    cogs1493 递推关系 矩阵
    cogs2557 天天爱跑步 LCA
    hdu4738 Caocao's Bridge Tarjan求割边
  • 原文地址:https://www.cnblogs.com/hustfly/p/3454569.html
Copyright © 2011-2022 走看看