- JPA 教程
- JPA - 首页
- JPA - 简介
- JPA - 架构
- JPA - ORM 组件
- JPA - 安装
- JPA - 实体管理器
- JPA - JPQL
- JPA - 高级映射
- JPA - 实体关系
- JPA - Criteria API
- JPA 有用资源
- JPA - 快速指南
- JPA - 有用资源
JPA - 高级映射
JPA 是一个随 Java 规范发布的库。因此,它支持实体持久化的所有面向对象概念。到目前为止,我们已经完成了对象关系映射的基础知识。本章将带您了解对象和关系实体之间的高级映射。
继承策略
继承是面向对象语言的核心概念,因此我们可以在实体之间使用继承关系或策略。JPA 支持三种类型的继承策略,例如 SINGLE_TABLE、JOINED_TABLE 和 TABLE_PER_CONCRETE_CLASS。
让我们考虑一个 Staff、TeachingStaff、NonTeachingStaff 类及其关系的示例,如下所示
在上图中,Staff 是一个实体,TeachingStaff 和 NonTeachingStaff 是 Staff 的子实体。在这里,我们将讨论上述示例在所有三种继承策略中的应用。
单表策略
单表策略获取所有类的字段(超类和子类),并将它们映射到一个称为 SINGLE_TABLE 策略的单个表中。这里,鉴别器值在区分一个表中三个实体的值方面起着关键作用。
让我们考虑上面的例子,TeachingStaff 和 NonTeachingStaff 是 Staff 类的子类。回想一下继承的概念(是从子类继承超类属性的机制),因此 sid、sname 是属于 TeachingStaff 和 NonTeachingStaff 的字段。创建一个 JPA 项目。该项目的所有模块如下所示
创建实体
在 ‘src’ 包下创建一个名为 ‘com.tutorialspoint.eclipselink.entity’ 的包。在给定包下创建一个名为 Staff.java 的新 Java 类。Staff 实体类如下所示
package com.tutorialspoint.eclipselink.entity;
import java.io.Serializable;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
@Entity
@Table
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
@DiscriminatorColumn( name = "type" )
public class Staff implements Serializable {
@Id
@GeneratedValue( strategy = GenerationType.AUTO )
private int sid;
private String sname;
public Staff( int sid, String sname ) {
super( );
this.sid = sid;
this.sname = sname;
}
public Staff( ) {
super( );
}
public int getSid( ) {
return sid;
}
public void setSid( int sid ) {
this.sid = sid;
}
public String getSname( ) {
return sname;
}
public void setSname( String sname ) {
this.sname = sname;
}
}
在上面的代码中,@DescriminatorColumn 指定字段名称 (type),其值显示其余的(Teaching 和 NonTeachingStaff)字段。
在 com.tutorialspoint.eclipselink.entity 包下,创建一个名为 TeachingStaff.java 的 Staff 类的子类(类)。TeachingStaff 实体类如下所示
package com.tutorialspoint.eclipselink.entity;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
@Entity
@DiscriminatorValue( value="TS" )
public class TeachingStaff extends Staff {
private String qualification;
private String subjectexpertise;
public TeachingStaff( int sid, String sname,
String qualification,String subjectexpertise ) {
super( sid, sname );
this.qualification = qualification;
this.subjectexpertise = subjectexpertise;
}
public TeachingStaff( ) {
super( );
}
public String getQualification( ){
return qualification;
}
public void setQualification( String qualification ){
this.qualification = qualification;
}
public String getSubjectexpertise( ) {
return subjectexpertise;
}
public void setSubjectexpertise( String subjectexpertise ){
this.subjectexpertise = subjectexpertise;
}
}
在 com.tutorialspoint.eclipselink.entity 包下,创建一个名为 NonTeachingStaff.java 的 Staff 类的子类(类)。NonTeachingStaff 实体类如下所示
package com.tutorialspoint.eclipselink.entity;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
@Entity
@DiscriminatorValue( value = "NS" )
public class NonTeachingStaff extends Staff {
private String areaexpertise;
public NonTeachingStaff( int sid, String sname, String areaexpertise ) {
super( sid, sname );
this.areaexpertise = areaexpertise;
}
public NonTeachingStaff( ) {
super( );
}
public String getAreaexpertise( ) {
return areaexpertise;
}
public void setAreaexpertise( String areaexpertise ){
this.areaexpertise = areaexpertise;
}
}
persistence.xml
persistence.xml 文件包含数据库配置信息和实体类的注册信息。xml 文件如下所示
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="Eclipselink_JPA" transaction-type="RESOURCE_LOCAL">
<class>com.tutorialspoint.eclipselink.entity.Staff</class>
<class>com.tutorialspoint.eclipselink.entity.NonTeachingStaff</class>
<class>com.tutorialspoint.eclipselink.entity.TeachingStaff</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://:3306/jpadb"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="eclipselink.logging.level" value="FINE"/>
<property name="eclipselink.ddl-generation" value="create-tables"/>
</properties>
</persistence-unit>
</persistence>
服务类
服务类是业务组件的实现部分。在 ‘src’ 包下创建一个名为 ‘com.tutorialspoint.eclipselink.service’ 的包。
在给定包下创建一个名为 SaveClient.java 的类,以存储 Staff、TeachingStaff 和 NonTeachingStaff 类的字段。SaveClient 类如下所示
package com.tutorialspoint.eclipselink.service;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import com.tutorialspoint.eclipselink.entity.NonTeachingStaff;
import com.tutorialspoint.eclipselink.entity.TeachingStaff;
public class SaveClient {
public static void main( String[ ] args ) {
EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" );
EntityManager entitymanager = emfactory.createEntityManager( );
entitymanager.getTransaction( ).begin( );
//Teaching staff entity
TeachingStaff ts1=new TeachingStaff(1,"Gopal","MSc MEd","Maths");
TeachingStaff ts2=new TeachingStaff(2, "Manisha", "BSc BEd", "English");
//Non-Teaching Staff entity
NonTeachingStaff nts1=new NonTeachingStaff(3, "Satish", "Accounts");
NonTeachingStaff nts2=new NonTeachingStaff(4, "Krishna", "Office Admin");
//storing all entities
entitymanager.persist(ts1);
entitymanager.persist(ts2);
entitymanager.persist(nts1);
entitymanager.persist(nts2);
entitymanager.getTransaction().commit();
entitymanager.close();
emfactory.close();
}
}
编译并执行上述程序后,您将在 Eclipse IDE 的控制台面板中收到通知。检查 MySQL Workbench 以获取输出。输出以表格格式显示如下
| Sid | 类型 | Sname | 专业领域 | 资格 | 学科专业 |
|---|---|---|---|---|---|
| 1 | TS | Gopal | MSC MED | 数学 | |
| 2 | TS | Manisha | BSC BED | 英语 | |
| 3 | NS | Satish | 会计 | ||
| 4 | NS | Krishna | 办公室行政 |
最后,您将获得一个包含所有三个类字段的单表,并由名为 ‘Type’(字段)的鉴别器列区分。
连接表策略
连接表策略是共享包含唯一值的引用列,以连接表并简化事务。让我们考虑与上面相同的示例。
创建一个 JPA 项目。所有项目模块如下所示
创建实体
在 ‘src’ 包下创建一个名为 ‘com.tutorialspoint.eclipselink.entity’ 的包。在给定包下创建一个名为 Staff.java 的新 Java 类。Staff 实体类如下所示
package com.tutorialspoint.eclipselink.entity;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
@Entity
@Table
@Inheritance( strategy = InheritanceType.JOINED )
public class Staff implements Serializable {
@Id
@GeneratedValue( strategy = GenerationType.AUTO )
private int sid;
private String sname;
public Staff( int sid, String sname ) {
super( );
this.sid = sid;
this.sname = sname;
}
public Staff( ) {
super( );
}
public int getSid( ) {
return sid;
}
public void setSid( int sid ) {
this.sid = sid;
}
public String getSname( ) {
return sname;
}
public void setSname( String sname ) {
this.sname = sname;
}
}
在 com.tutorialspoint.eclipselink.entity 包下,创建一个名为 TeachingStaff.java 的 Staff 类的子类(类)。TeachingStaff 实体类如下所示
package com.tutorialspoint.eclipselink.entity;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
@Entity
@PrimaryKeyJoinColumn(referencedColumnName="sid")
public class TeachingStaff extends Staff {
private String qualification;
private String subjectexpertise;
public TeachingStaff( int sid, String sname,
String qualification,String subjectexpertise ) {
super( sid, sname );
this.qualification = qualification;
this.subjectexpertise = subjectexpertise;
}
public TeachingStaff( ) {
super( );
}
public String getQualification( ){
return qualification;
}
public void setQualification( String qualification ){
this.qualification = qualification;
}
public String getSubjectexpertise( ) {
return subjectexpertise;
}
public void setSubjectexpertise( String subjectexpertise ){
this.subjectexpertise = subjectexpertise;
}
}
在 com.tutorialspoint.eclipselink.entity 包下,创建一个名为 NonTeachingStaff.java 的 Staff 类的子类(类)。NonTeachingStaff 实体类如下所示
package com.tutorialspoint.eclipselink.entity;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
@Entity
@PrimaryKeyJoinColumn(referencedColumnName="sid")
public class NonTeachingStaff extends Staff {
private String areaexpertise;
public NonTeachingStaff( int sid, String sname, String areaexpertise ) {
super( sid, sname );
this.areaexpertise = areaexpertise;
}
public NonTeachingStaff( ) {
super( );
}
public String getAreaexpertise( ) {
return areaexpertise;
}
public void setAreaexpertise( String areaexpertise ) {
this.areaexpertise = areaexpertise;
}
}
persistence.xml
persistence.xml 文件包含数据库配置信息和实体类的注册信息。xml 文件如下所示
<?xml version = "1.0" encoding = "UTF-8"?>
<persistence version = "2.0" xmlns = "http://java.sun.com/xml/ns/persistence"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name = "Eclipselink_JPA" transaction-type = "RESOURCE_LOCAL">
<class>com.tutorialspoint.eclipselink.entity.Staff</class>
<class>com.tutorialspoint.eclipselink.entity.NonTeachingStaff</class>
<class>com.tutorialspoint.eclipselink.entity.TeachingStaff</class>
<properties>
<property name = "javax.persistence.jdbc.url" value = "jdbc:mysql://:3306/jpadb"/>
<property name = "javax.persistence.jdbc.user" value = "root"/>
<property name = "javax.persistence.jdbc.password" value = "root"/>
<property name = "javax.persistence.jdbc.driver" value = "com.mysql.jdbc.Driver"/>
<property name = "eclipselink.logging.level" value = "FINE"/>
<property name = "eclipselink.ddl-generation" value = "create-tables"/>
</properties>
</persistence-unit>
</persistence>
服务类
服务类是业务组件的实现部分。在 ‘src’ 包下创建一个名为 ‘com.tutorialspoint.eclipselink.service’ 的包。
在给定包下创建一个名为 SaveClient.java 的类,以存储 Staff、TeachingStaff 和 NonTeachingStaff 类的字段。然后 SaveClient 类如下所示
package com.tutorialspoint.eclipselink.service;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import com.tutorialspoint.eclipselink.entity.NonTeachingStaff;
import com.tutorialspoint.eclipselink.entity.TeachingStaff;
public class SaveClient {
public static void main( String[ ] args ) {
EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" );
EntityManager entitymanager = emfactory.createEntityManager( );
entitymanager.getTransaction( ).begin( );
//Teaching staff entity
TeachingStaff ts1 = new TeachingStaff(1,"Gopal","MSc MEd","Maths");
TeachingStaff ts2 = new TeachingStaff(2, "Manisha", "BSc BEd", "English");
//Non-Teaching Staff entity
NonTeachingStaff nts1 = new NonTeachingStaff(3, "Satish", "Accounts");
NonTeachingStaff nts2 = new NonTeachingStaff(4, "Krishna", "Office Admin");
//storing all entities
entitymanager.persist(ts1);
entitymanager.persist(ts2);
entitymanager.persist(nts1);
entitymanager.persist(nts2);
entitymanager.getTransaction().commit();
entitymanager.close();
emfactory.close();
}
}
编译并执行上述程序后,您将在 Eclipse IDE 的控制台面板中收到通知。要查看输出,请检查 MySQL Workbench,如下所示
这里创建了三个表,staff 表的结果以表格格式显示如下
| Sid | Dtype | Sname |
|---|---|---|
| 1 | TeachingStaff | Gopal |
| 2 | TeachingStaff | Manisha |
| 3 | NonTeachingStaff | Satish |
| 4 | NonTeachingStaff | Krishna |
TeachingStaff 表的结果以表格格式显示如下
| Sid | 资格 | 学科专业 |
|---|---|---|
| 1 | MSC MED | 数学 |
| 2 | BSC BED | 英语 |
在上表中,sid 是外键(来自 staff 表的引用字段)。NonTeachingStaff 表的结果以表格格式显示如下
| Sid | 专业领域 |
|---|---|
| 3 | 会计 |
| 4 | 办公室行政 |
最后,使用各自的字段创建了三个表,并且 SID 字段由所有三个表共享。在 staff 表中,SID 是主键,在其余的(TeachingStaff 和 NonTeachingStaff)表中,SID 是外键。
每个类表策略
每个类表策略是为每个子实体创建一个表。将创建 staff 表,但它将包含空记录。Staff 表的字段值必须由 TeachingStaff 和 NonTeachingStaff 表共享。
让我们考虑与上面相同的示例。该项目的所有模块如下所示
创建实体
在 ‘src’ 包下创建一个名为 ‘com.tutorialspoint.eclipselink.entity’ 的包。在给定包下创建一个名为 Staff.java 的新 Java 类。Staff 实体类如下所示
package com.tutorialspoint.eclipselink.entity;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
@Entity
@Table
@Inheritance( strategy = InheritanceType.TABLE_PER_CLASS )
public class Staff implements Serializable {
@Id
@GeneratedValue( strategy = GenerationType.AUTO )
private int sid;
private String sname;
public Staff( int sid, String sname ) {
super( );
this.sid = sid;
this.sname = sname;
}
public Staff( ) {
super( );
}
public int getSid( ) {
return sid;
}
public void setSid( int sid ) {
this.sid = sid;
}
public String getSname( ) {
return sname;
}
public void setSname( String sname ) {
this.sname = sname;
}
}
在 com.tutorialspoint.eclipselink.entity 包下,创建一个名为 TeachingStaff.java 的 Staff 类的子类(类)。TeachingStaff 实体类如下所示
package com.tutorialspoint.eclipselink.entity;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
@Entity
public class TeachingStaff extends Staff {
private String qualification;
private String subjectexpertise;
public TeachingStaff( int sid, String sname, String qualification, String subjectexpertise ) {
super( sid, sname );
this.qualification = qualification;
this.subjectexpertise = subjectexpertise;
}
public TeachingStaff( ) {
super( );
}
public String getQualification( ){
return qualification;
}
public void setQualification( String qualification ) {
this.qualification = qualification;
}
public String getSubjectexpertise( ) {
return subjectexpertise;
}
public void setSubjectexpertise( String subjectexpertise ){
this.subjectexpertise = subjectexpertise;
}
}
在 com.tutorialspoint.eclipselink.entity 包下,创建一个名为 NonTeachingStaff.java 的 Staff 类的子类(类)。NonTeachingStaff 实体类如下所示
package com.tutorialspoint.eclipselink.entity;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
@Entity
public class NonTeachingStaff extends Staff {
private String areaexpertise;
public NonTeachingStaff( int sid, String sname, String areaexpertise ) {
super( sid, sname );
this.areaexpertise = areaexpertise;
}
public NonTeachingStaff( ) {
super( );
}
public String getAreaexpertise( ) {
return areaexpertise;
}
public void setAreaexpertise( String areaexpertise ) {
this.areaexpertise = areaexpertise;
}
}
persistence.xml
persistence.xml 文件包含数据库配置信息和实体类的注册信息。xml 文件如下所示
<?xml version="1.0" encoding = "UTF-8"?>
<persistence version = "2.0" xmlns = "http://java.sun.com/xml/ns/persistence"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name = "Eclipselink_JPA" transaction-type = "RESOURCE_LOCAL">
<class>com.tutorialspoint.eclipselink.entity.Staff</class>
<class>com.tutorialspoint.eclipselink.entity.NonTeachingStaff</class>
<class>com.tutorialspoint.eclipselink.entity.TeachingStaff</class>
<properties>
<property name = "javax.persistence.jdbc.url" value = "jdbc:mysql://:3306/jpadb"/>
<property name = "javax.persistence.jdbc.user" value = "root"/>
<property name = "javax.persistence.jdbc.password" value = "root"/>
<property name = "javax.persistence.jdbc.driver" value = "com.mysql.jdbc.Driver"/>
<property name = "eclipselink.logging.level" value = "FINE"/>
<property name = "eclipselink.ddl-generation" value="create-tables"/>
</properties>
</persistence-unit>
</persistence>
服务类
服务类是业务组件的实现部分。在 ‘src’ 包下创建一个名为 ‘com.tutorialspoint.eclipselink.service’ 的包。
在给定包下创建一个名为 SaveClient.java 的类,以存储 Staff、TeachingStaff 和 NonTeachingStaff 类的字段。SaveClient 类如下所示
package com.tutorialspoint.eclipselink.service;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import com.tutorialspoint.eclipselink.entity.NonTeachingStaff;
import com.tutorialspoint.eclipselink.entity.TeachingStaff;
public class SaveClient {
public static void main( String[ ] args ) {
EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" );
EntityManager entitymanager = emfactory.createEntityManager( );
entitymanager.getTransaction( ).begin( );
//Teaching staff entity
TeachingStaff ts1 = new TeachingStaff(1,"Gopal","MSc MEd","Maths");
TeachingStaff ts2 = new TeachingStaff(2, "Manisha", "BSc BEd", "English");
//Non-Teaching Staff entity
NonTeachingStaff nts1 = new NonTeachingStaff(3, "Satish", "Accounts");
NonTeachingStaff nts2 = new NonTeachingStaff(4, "Krishna", "Office Admin");
//storing all entities
entitymanager.persist(ts1);
entitymanager.persist(ts2);
entitymanager.persist(nts1);
entitymanager.persist(nts2);
entitymanager.getTransaction().commit();
entitymanager.close();
emfactory.close();
}
}
编译并执行上述程序后,您将在 Eclipse IDE 的控制台面板中收到通知。要查看输出,请检查 MySQL Workbench,如下所示
这里创建了三个表,Staff 表包含空记录。
TeachingStaff 的结果以表格格式显示如下
| Sid | 资格 | Sname | 学科专业 |
|---|---|---|---|
| 1 | MSC MED | Gopal | 数学 |
| 2 | BSC BED | Manisha | 英语 |
上表 TeachingStaff 包含 Staff 和 TeachingStaff 实体的字段。
NonTeachingStaff 的结果以表格格式显示如下
| Sid | 专业领域 | Sname |
|---|---|---|
| 3 | 会计 | Satish |
| 4 | 办公室行政 | Krishna |
上表 NonTeachingStaff 包含 Staff 和 NonTeachingStaff 实体的字段。