OpenJPA

 

7 Inheritance
    对象使用引用以便关联到其它对象;关系型数据库表之间采用外键来描述表的关系。在关系型数据库中通常没有自然且有效的方法来描述类的继承关系。JPA通过Inheritance annotation提供了几种继承策略,它有以下属性:

  • InheritanceType strategy:用来声明继承策略。可选值是InheritanceType.SINGLE_TABLE、InheritanceType.JOINED和InheritanceType .TABLE_PER_CLASS。缺省值是InheritanceType.SINGLE_TABLE。

   关于Inheritance的更多内容,可以参考Hibernate实战by Christian Bauer, Gavin King。

 

7.1 Single Table
    InheritanceType.SINGLE_TABLE 策略为类的继承体系采用同一个表。表名是基类的名称。例如:

 

 

 

  1. @Entity  
  2. @Inheritance(strategy=InheritanceType.SINGLE_TABLE)   
  3. public class Base {   
  4.     @Id  
  5.     private int id;   
  6.        
  7.     @Basic  
  8.     private String baseName;   
  9. }   
  10.   
  11. @Entity  
  12. public class Derived1 extends Base {   
  13.     @Basic  
  14.     private String derived1Name;   
  15. }   
  16.   
  17. @Entity  
  18. public class Derived2 extends Base {   
  19.     @Basic  
  20.     private String derived2Name;   
  21. }  

 

  使用MappingTool建立的表结构如下:

 

 

  1. mysql> describe base;   
  2. +--------------+--------------+------+-----+---------+----------------+   
  3. | Field        | Type         | Null | Key | Default | Extra          |   
  4. +--------------+--------------+------+-----+---------+----------------+   
  5. | id           | int(11)      | NO   | PRI | NULL    | auto_increment |   
  6. | baseName     | varchar(255) | YES  |     | NULL    |                |   
  7. | DTYPE        | varchar(255) | YES  | MUL | NULL    |                |   
  8. | derived1Name | varchar(255) | YES  |     | NULL    |                |   
  9. | derived2Name | varchar(255) | YES  |     | NULL    |                |   
  10. +--------------+--------------+------+-----+---------+----------------+   

 

 

  1. EntityManager em = entityManagerFactory.createEntityManager();   
  2. em.getTransaction().begin();   
  3. Base base = new Base();   
  4. base.setBaseName("base");   
  5. em.persist(base);   
  6. Derived1 d1 = new Derived1();   
  7. d1.setBaseName("derived1's base");   
  8. d1.setDerived1Name("derived1");   
  9. em.persist(d1);   
  10. Derived2 d2 = new Derived2();   
  11. d2.setBaseName("derived2's base");   
  12. d2.setDerived2Name("derived2");   
  13. em.persist(d2);   
  14. em.getTransaction().commit();   
  15. em.close();  

 

以上代码执行后,数据库中base表的数据如下(其中DTYPE列由OpenJPA自动插入,用于区分不同的class,关于Discriminator的详细用法请参考OpenJPA User's Guide):

 

  • mysql> select * from base;   
  • +----+-----------------+----------+--------------+--------------+   
  • | id | baseName        | DTYPE    | derived1Name | derived2Name |   
  • +----+-----------------+----------+--------------+--------------+   
  • |  1 | base            | Base     | NULL         | NULL         |   
  • |  2 | derived1's base | Derived1 | derived1     | NULL         |   
  • |  3 | derived2's base | Derived2 | NULL         | derived2     |   
  • +----+-----------------+----------+--------------+--------------+  
  •  

     

     

    7.1.1 Advantages
        InheritanceType.SINGLE_TABLE 策略的优势在于简单且性能高(因为不需要使用连接查询等)。如果类的继承体系中,子类和父类间的差异主要在于行为,同时子类之间以及子类和父类之间的属性差异不大(例如子类不增加属性或者增加的属性数目比较少),那么适用于这个策略。

    7.1.2 Disadvantages
        这个策略导致规范化级别降低。由于类继承体系中的每个类的属性都要映射到表的一列,因此当类的继承体系变的复杂的时候,表也随之变大。子类中属性对应的列必须声明为nullable。

     

    7.2 Joined
        InheritanceType.JOINED策略为类继承体系中的每个类创建不同的表。每个表只包含类中定义的列,因此在load一个子类的时候,JPA实现需要同时查询子类映射的表,以及通过关联查询所有的父类映射的表。PrimaryKeyJoinColumn annotation用来指定子类映射的表如何关联到父类映射的表。它有以下属性:

    • String name: 子类映射表中的列名。如果只有一个identity filed,那么缺省使用这个field对应的列名。
    • String referencedColumnName: 父类映射表中用来关联的列名。如果只有一个identity filed,那么缺省使用这个field对应的列名。
    • String columnDefinition: 数据库中列的数据类型。只有当JPA vendor支持通过metadata创建表的时候,这个属性才被使用。

       以下是个简单的例子:

     

     

     

    1. @Entity  
    2. @Inheritance(strategy=InheritanceType.JOINED)   
    3. public class Base {   
    4.     @Id  
    5.     @GeneratedValue(strategy = GenerationType.IDENTITY)   
    6.     private int id;   
    7.        
    8.     @Basic  
    9.     private String baseName;   
    10. }   
    11.   
    12. @Entity  
    13. @PrimaryKeyJoinColumn(name="id", referencedColumnName="id")   
    14. public class Derived1 extends Base {   
    15.     @Basic  
    16.     private String derived1Name;   
    17. }   
    18.   
    19. @Entity  
    20. @PrimaryKeyJoinColumn(name="id", referencedColumnName="id")   
    21. public class Derived2 extends Base {   
    22.     @Basic  
    23.     private String derived2Name;   
    24. }  
    25. 使用MappingTool建立的表结构如下:

     

     

    1. mysql> describe base;   
    2. +----------+--------------+------+-----+---------+----------------+   
    3. | Field    | Type         | Null | Key | Default | Extra          |   
    4. +----------+--------------+------+-----+---------+----------------+   
    5. | id       | int(11)      | NO   | PRI | NULL    | auto_increment |   
    6. | baseName | varchar(255) | YES  |     | NULL    |                |   
    7. +----------+--------------+------+-----+---------+----------------+   
    8.   
    9. mysql> describe derived1;   
    10. +--------------+--------------+------+-----+---------+-------+   
    11. | Field        | Type         | Null | Key | Default | Extra |   
    12. +--------------+--------------+------+-----+---------+-------+   
    13. | id           | int(11)      | NO   | PRI |         |       |   
    14. | derived1Name | varchar(255) | YES  |     | NULL    |       |   
    15. +--------------+--------------+------+-----+---------+-------+   
    16.   
    17. mysql> describe derived2;   
    18. +--------------+--------------+------+-----+---------+-------+   
    19. | Field        | Type         | Null | Key | Default | Extra |   
    20. +--------------+--------------+------+-----+---------+-------+   
    21. | id           | int(11)      | NO   | PRI |         |       |   
    22. | derived2Name | varchar(255) | YES  |     | NULL    |       |   
    23. +--------------+--------------+------+-----+---------+-------+  

     

     

    1. EntityManager em = entityManagerFactory.createEntityManager();   
    2. em.getTransaction().begin();   
    3. Base base = new Base();   
    4. base.setBaseName("base");   
    5. em.persist(base);   
    6. Derived1 d1 = new Derived1();   
    7. d1.setBaseName("derived1's base");   
    8. d1.setDerived1Name("derived1");   
    9. em.persist(d1);   
    10. Derived2 d2 = new Derived2();   
    11. d2.setBaseName("derived2's base");   
    12. d2.setDerived2Name("derived2");   
    13. em.persist(d2);   
    14. em.getTransaction().commit();   
    15. em.close();  

     

    以上代码执行后,数据库中base表的数据如下:

     

    1. mysql> select * from base;   
    2. +----+-----------------+   
    3. | id | baseName        |   
    4. +----+-----------------+   
    5. |  1 | derived2's base |   
    6. |  2 | derived1's base |   
    7. |  3 | base            |   
    8. +----+-----------------+   
    9.   
    10. mysql> select * from derived1;   
    11. +----+--------------+   
    12. | id | derived1Name |   
    13. +----+--------------+   
    14. |  2 | derived1     |   
    15. +----+--------------+   
    16.   
    17. mysql> select * from derived2;   
    18. +----+--------------+   
    19. | id | derived2Name |   
    20. +----+--------------+   
    21. |  1 | derived2     |   
    22. +----+--------------+  

     

     

     

    7.2.1 Advantages
        InheritanceType. JOINED策略的优势在于数据库表中没有冗余字段,因此规范化级别比较高;当有新的子类加入到类的继承体系中时,已有表的schema无须修改。如果类的继承体系中,子类和父类间的差异不在于行为,同时子类间的属性差异比较大,那么适用于这个策略。

    7.2.2 Disadvantages
        由于在查询的时候需要进行关联,那么查询的速度会比其它方式慢。此外可能需要多个插入和更新语句来处理多个表。

     

    7.3 Table Per Class
        InheritanceType.TABLE_PER_CLASS策略为类继承体系中的每个类创建不同的表。和InheritanceType.JOINED策略不同的是,每个表中包含所有的子类和父类中定义的所有列。因此在load一个子类的时候,JPA实现只需要同时查询子类映射的表。
        以下是个简单的例子:

     

     

     

    1. @Entity  
    2. @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)   
    3. public class Base {   
    4.     @Id  
    5.     @GeneratedValue(strategy = GenerationType.IDENTITY)   
    6.     private int id;   
    7.        
    8.     @Basic  
    9.     private String baseName;   
    10. }   
    11.   
    12. @Entity  
    13. public class Derived1 extends Base {   
    14.     @Basic  
    15.     private String derived1Name;   
    16. }   
    17.   
    18. @Entity  
    19. public class Derived2 extends Base {   
    20.     @Basic  
    21.     private String derived2Name;   
    22. }  

     

     

       使用MappingTool建立的表结构如下:

    1. mysql> describe base;   
    2. +----------+--------------+------+-----+---------+----------------+   
    3. | Field    | Type         | Null | Key | Default | Extra          |   
    4. +----------+--------------+------+-----+---------+----------------+   
    5. | id       | int(11)      | NO   | PRI | NULL    | auto_increment |   
    6. | baseName | varchar(255) | YES  |     | NULL    |                |   
    7. +----------+--------------+------+-----+---------+----------------+   
    8.   
    9. mysql> describe derived1;   
    10. +--------------+--------------+------+-----+---------+----------------+   
    11. | Field        | Type         | Null | Key | Default | Extra          |   
    12. +--------------+--------------+------+-----+---------+----------------+   
    13. | id           | int(11)      | NO   | PRI | NULL    | auto_increment |   
    14. | baseName     | varchar(255) | YES  |     | NULL    |                |   
    15. | derived1Name | varchar(255) | YES  |     | NULL    |                |   
    16. +--------------+--------------+------+-----+---------+----------------+   
    17.   
    18. mysql> describe derived2;   
    19. +--------------+--------------+------+-----+---------+----------------+   
    20. | Field        | Type         | Null | Key | Default | Extra          |   
    21. +--------------+--------------+------+-----+---------+----------------+   
    22. | id           | int(11)      | NO   | PRI | NULL    | auto_increment |   
    23. | baseName     | varchar(255) | YES  |     | NULL    |                |   
    24. | derived2Name | varchar(255) | YES  |     | NULL    |                |   
    25. +--------------+--------------+------+-----+---------+----------------+  

    1. EntityManager em = entityManagerFactory.createEntityManager();   
    2. em.getTransaction().begin();   
    3. Base base = new Base();   
    4. base.setBaseName("base");   
    5. em.persist(base);   
    6. Derived1 d1 = new Derived1();   
    7. d1.setBaseName("derived1's base");   
    8. d1.setDerived1Name("derived1");   
    9. em.persist(d1);   
    10. Derived2 d2 = new Derived2();   
    11. d2.setBaseName("derived2's base");   
    12. d2.setDerived2Name("derived2");   
    13. em.persist(d2);   
    14. em.getTransaction().commit();   
    15. em.close();  

        以上代码执行后,数据库中base表的数据如下: 

     

    1. mysql> select * from base;   
    2. +----+----------+   
    3. | id | baseName |   
    4. +----+----------+   
    5. |  1 | base     |   
    6. +----+----------+   
    7.   
    8. mysql> select * from derived1;   
    9. +----+-----------------+--------------+   
    10. | id | baseName        | derived1Name |   
    11. +----+-----------------+--------------+   
    12. |  1 | derived1's base | derived1     |   
    13. +----+-----------------+--------------+   
    14.   
    15. mysql> select * from derived2;   
    16. +----+-----------------+--------------+   
    17. | id | baseName        | derived2Name |   
    18. +----+-----------------+--------------+   
    19. |  1 | derived2's base | derived2     |   
    20. +----+-----------------+--------------+  

    7.3.1 Advantages
        对于已知class类型的实例来说,这个策略十分有效。跟InheritanceType.JOINED策略类似,当有新的子类加入到类的继承体系中时,已有表的schema无须修改。

    7.3.2 Disadvantages
        这个策略在处理多态关系的时候会存在很多限制,此时某个引用(或者集合中的引用)可能指向任何子类的实例。由于无法使用关联查询,因此在查询的时候可能需要使用多个SQL语句或者使用UNION。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值