注:文章中据说的实体指的是被@Entity注解的类。
JPA中对象关系映射通常情况下是一个实体对应一个表,两个实体之间没有任何关系。如果两个实体之间是继承关系,那么该如何映射呢?
JPA中的实体支持继承映射,多态关联,多态查询。抽象类和具体的类都可以是实体,且都可以使用@Entity来注解,映射成实体,并查询封装成一个实体。实体类可以继承非实体类,非实体类也可以继承实体类。
JPA的继承映射有如下几种情况:
一、实体类继承抽象(具体)实体类
抽象类可以指定成为一个实体,抽象实体和具体实体的唯一区别只是抽象实体不能够被直接实例化。抽象实体能够被映射成一个实体并能够作为查询目标。
抽象实体类使用@Entity注解或在XML描述符表示成一个实体。
这种映射相对复杂,后面会专门写一篇文章来举例说明。这里就不再多说。
二、实体类继承映射超类(Mapped Superclasses)
实体可以继承自一个超类,这个超类提供了持久化实体状态(即属性或字段)和映射信息,但它本身不是一个实体。通常情况下,这种超类映射的的目的是定义多个实体共有的状态和映射信息。
映射超类和实体不一样,它不能够被查询,所以不能作为参数传递给EntityManager或Query 接口进行操作。映射超类定义的持久化关系必须是单向的。
抽象类或具体的类都可以作为映射超类,使用@MappedSuperclass注解(或mapped-superclass XML描述符元素)来指定映射超类。
映射超类不会生成单独的表,它的映射信息作用于继承自它的实体类。
映射超类能够像实体类一样被映射,只是它的映射将作用于继承自它的实体类,因为它本身不存在单独的表。当作用于子类时,继承的映射信息将作用于子类对应的表上。子类可以通过@AttributeOverride和AssociationOverride注解或对应的XML描述符元素来覆盖映射超类的映射信息。下面来看一个实例:
- package com.mikan;
- import java.io.Serializable;
- import javax.persistence.Column;
- import javax.persistence.GeneratedValue;
- import javax.persistence.GenerationType;
- import javax.persistence.Id;
- import javax.persistence.MappedSuperclass;
- @MappedSuperclass
- public class Employee implements Serializable {
- private static final long serialVersionUID = -7674269980281525370L;
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- protected Integer empId;
- @Column
- protected String name;
- // getter/setter方法
- }
- package com.mikan;
- import javax.persistence.Column;
- import javax.persistence.Entity;
- import javax.persistence.Table;
- @Entity
- @Table(name = "FT_EMP")
- public class FullTimeEmployee extends Employee {
- private static final long serialVersionUID = 9115429216382631425L;
- // 继承映射超类的empId和name属性
- @Column
- private Double salary;
- // getter/setter方法
- }
- package com.mikan;
- import javax.persistence.Column;
- import javax.persistence.Entity;
- import javax.persistence.Table;
- @Entity
- @Table(name = "PT_EMP")
- public class PartTimeEmployee extends Employee {
- private static final long serialVersionUID = -6122347374515830424L;
- // 继承映射超类的empId和name属性
- @Column(name = "hourly_wage")
- private Float hourlyWage;
- // getter/setter方法
- }
三、实体类继承非实体类
一个实体类可以继承一个非实体超类,这个非实体超类可以是具体的类,也可以是抽象类。
这个非实体超类仅被作为一种继承行为,它的状态不会被持久化。所有继承自非实体超类的状态(即属性或字段)在实体子类中都不会被持久化,实体管理器不会管理这些状态。非实体超类上的所有注解都会被忽略。非实体超类不能作为参数传递给EntityManager或Query 接口进行操作。
下面来看一个实例:
- public class Cart {
- protected Integer operationCount; // transient state
- public Cart() {
- operationCount = 0;
- }
- public Integer getOperationCount() {
- return operationCount;
- }
- public void incrementOperationCount() {
- operationCount++;
- }
- }
- @Entity
- public class ShoppingCart extends Cart {
- Collection<Item> items = new Vector<Item>();
- public ShoppingCart() {
- super();
- }
- @OneToMany
- public Collection<Item> getItems() {
- return items;
- }
- public void addItem(Item item) {
- items.add(item);
- incrementOperationCount();
- }
- }
ShoppingCart对应的表中不会包含operationCount字段。