在正式了解 @SecondaryTable 注解用法之前,我们先看看一个关于主表(users)和子表(users_ext)的实例:
上图中,users 为主表,该表记录了用户主要信息;users_ext 为子表(也称为附表),该表用来记录用户的扩展信息。我们可以使用 @SecondaryTable 注解将一个实体中的数据分别存储到不同的数据表中。
@SecondaryTable 注解的主要用是将主表提取成公共表,子表是自行定义。@SecondaryTable 和 @Table 注解一样,也支持如下属性:
name
该属性用于指定数据库表名称,即主表的附表名称;例如:
// users_ext 为副表 @SecondaryTable(name = "users_ext", pkJoinColumns = @PrimaryKeyJoinColumn(name = "user_id") )
catalog
可选属性,用于指定数据库实例名,一般来说 persistence.xml 文件中必须指定数据库 url,url 中将包含数据库实例;
schema
作用与 catalog 属性作用一致,可自行测试;
uniqueConstraints
该属性用于设定约束条件,即唯一性约束;
pkJoinColumns
指定用于和主表连接的列;例如:
// user_id 用来和主表进行关联 @SecondaryTable(name = "users_ext", pkJoinColumns = @PrimaryKeyJoinColumn(name = "user_id") )
使用 @SecondaryTable 将 users 和 users_ext 表进行关联(根据 user_id 列进行关联),将 User7 实体中的数据分别存储到 users 主表 和 users_ext 附表。代码如下:
@Entity @Table(name = "users") @SecondaryTable(name = "users_ext", pkJoinColumns = @PrimaryKeyJoinColumn(name = "user_id") ) public class User7 { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(table = "users") private Integer id; @Column(name = "name", table = "users") private String name; @Column(precision = 8, table = "users") private Integer age; // 下面字段数据来自 users_ext 表 @Column(name = "user_id", table = "users_ext") private Integer userId; @Column(name = "email", table = "users_ext") private String email; @Column(name = "home_url", table = "users_ext") private String homeUrl; }
客户端代码,使用 EntityManager 实例插入和查询 User7 对应的数据,代码如下:
import com.alibaba.fastjson.JSONObject; import com.huangx.openjpa.annotation.entity.User7; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.Query; import java.util.List; public class OpenJpaDemo7 { /** 持久化单元名称 */ private static final String NAME = "openJPA"; public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory(NAME); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); // INSERT User7 user = new User7(); user.setName("武松-" + System.currentTimeMillis()); user.setAge(27); user.setEmail("wusong@outlook.com"); user.setHomeUrl("http://www.wusong.com/index.html"); em.persist(user); // SELECT String qlString = "select t from User7 t"; Query query = em.createQuery(qlString); List<User7> userList = (List<User7>) query.getResultList(); for (User7 item : userList) { System.out.println(JSONObject.toJSONString(item)); } em.getTransaction().commit(); em.close(); emf.close(); System.out.println("finished."); } }
如果在 @Entity 实体上未指定 @SecondaryTable 注释,则实体的所有可持久化字段或属性都映射到主表。
如果注释 @SecondaryTable 未指定主键连接列(pkJoinColumns 属性),则假设连接列引用主表的主键列。实例:
@Entity @Table(name = "users") @SecondaryTable(name = "users_ext2") public class User9 { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(table = "users") private Integer id; @Column(name = "name", table = "users") private String name; @Column(precision = 8, table = "users") private Integer age; // 下面字段数据来自 users_ext 表 @Column(name = "email", table = "users_ext2") private String email; @Column(name = "home_url", table = "users_ext2") private String homeUrl; }
等价于
@SecondaryTable(name = "users_ext2", pkJoinColumns = { @PrimaryKeyJoinColumn(name = "USER9_ID") }
上面实例将自动在 users_ext 表中创建一个 user9_id 字段来存放关联主键,SQL 脚本如下:
CREATE TABLE `users_ext2` ( `email` varchar(255) DEFAULT NULL, `home_url` varchar(255) DEFAULT NULL, `USER9_ID` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
该注解用来为一个实体指定多个辅助表。例如:
实例1:多个辅助表假设所有表中的主键列名称相同。
@Entity @Table(name="users") @SecondaryTables({ @SecondaryTable(name="users_ext"), @SecondaryTable(name="users_ext2") }) public class User9 { // ... }
实例2:具有不同名称的主键列的多个辅助表。
@Entity @Table(name="users") @SecondaryTables({ @SecondaryTable(name="users_ext", pkJoinColumns=@PrimaryKeyJoinColumn(name="user_id")), @SecondaryTable(name="users_ext2", pkJoinColumns=@PrimaryKeyJoinColumn(name="user9_id")) }) public class User9 { // ... }