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 项目。本项目所有模块如下:创建实体
创建一个名为的包 ‘com.jc2182.eclipselink.entity’ 在下面 ‘src’包裹。创建一个名为的新 java 类Staff.java在给定的包下。Staff实体类如下所示:package com.jc2182.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)字段。创建一个名为 Staff 类的子类(类) TeachingStaff.java 在下面 com.jc2182.eclipselink.entity包裹。TeachingStaff 实体类如下所示:package com.jc2182.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; } }
创建一个名为 Staff 类的子类(类) NonTeachingStaff.java 在下面 com.jc2182.eclipselink.entity包裹。NonTeachingStaff 实体类如下所示:package com.jc2182.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 文件包含数据库的配置信息和实体类的注册信息。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.jc2182.eclipselink.entity.Staff</class> <class>com.jc2182.eclipselink.entity.NonTeachingStaff</class> <class>com.jc2182.eclipselink.entity.TeachingStaff</class> <properties> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost: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.jc2182.eclipselink.service’.在给定的包下创建一个名为 SaveClient.java 的类来存储 Staff、TeachingStaff 和 NonTeachingStaff 类字段。SaveClient 类如下所示:package com.jc2182.eclipselink.service; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import com.jc2182.eclipselink.entity.NonTeachingStaff; import com.jc2182.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 工作台的输出。表格格式的输出如下所示:Sid Type Sname Areaexpertise Qualification Subjectexpertise 1 TS Gopal MSC MED Maths 2 TS Manisha BSC BED English 3 NS Satish Accounts 4 NS Krishna Office Admin 最后,您将获得包含所有三个类的字段的单个表,并且与名为的鉴别器列不同 ‘Type’ (字段)。 -
连接表策略
连接表策略是共享包含唯一值的引用列以连接表并进行轻松事务。让我们考虑与上面相同的例子。创建一个 JPA 项目。所有项目模块如下所示:创建实体
创建一个名为的包 ‘com.jc2182.eclipselink.entity’ 在下面 ‘src’包裹。创建一个名为的新 java 类Staff.java在给定的包下。Staff实体类如下所示:package com.jc2182.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; } }
创建一个名为 Staff 类的子类(类) TeachingStaff.java 在下面 com.jc2182.eclipselink.entity包裹。TeachingStaff 实体类如下所示:package com.jc2182.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; } }
创建一个名为 Staff 类的子类(类) NonTeachingStaff.java 在下面 com.jc2182.eclipselink.entity包裹。NonTeachingStaff 实体类如下所示:package com.jc2182.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 文件包含数据库的配置信息和实体类的注册信息。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.jc2182.eclipselink.entity.Staff</class> <class>com.jc2182.eclipselink.entity.NonTeachingStaff</class> <class>com.jc2182.eclipselink.entity.TeachingStaff</class> <properties> <property name = "javax.persistence.jdbc.url" value = "jdbc:mysql://localhost: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.jc2182.eclipselink.service’.在给定的包下创建一个名为 SaveClient.java 的类来存储 Staff、TeachingStaff 和 NonTeachingStaff 类字段。然后 SaveClient 类如下:package com.jc2182.eclipselink.service; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import com.jc2182.eclipselink.entity.NonTeachingStaff; import com.jc2182.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 工作台如下:这里创建了三个表,结果如下 staff 表格形式的表格如下所示:Sid Dtype Sname 1 TeachingStaff Gopal 2 TeachingStaff Manisha 3 NonTeachingStaff Satish 4 NonTeachingStaff Krishna TeachingStaff的结果表格形式的表格如下所示:Sid Qualification Subjectexpertise 1 MSC MED Maths 2 BSC BED English 上表中sid为外键(参考字段表staff表)的结果 NonTeachingStaff 表格形式的表格如下所示:Sid Areaexpertise 3 Accounts 4 Office Admin 最后,三个表分别使用它们的字段创建,SID 字段由所有三个表共享。在人员表中 SID 是主键,在其余(TeachingStaff 和 NonTeachingStaff)表中 SID 是外键。 -
每班策略表
Table per class 策略是为每个子实体创建一个表。将创建员工表,但它将包含空记录。Staff 表的字段值必须由 TeachingStaff 和 NonTeachingStaff 表共享。让我们考虑与上面相同的例子。本项目所有模块如下图所示:创建实体
创建一个名为的包 ‘com.jc2182.eclipselink.entity’ 在下面 ‘src’包裹。创建一个名为的新 java 类Staff.java在给定的包下。Staff实体类如下所示:package com.jc2182.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; } }
创建一个名为 Staff 类的子类(类) TeachingStaff.java 在下面 com.jc2182.eclipselink.entity包裹。TeachingStaff 实体类如下所示:package com.jc2182.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; } }
创建一个名为 Staff 类的子类(类) NonTeachingStaff.java 在下面 com.jc2182.eclipselink.entity包裹。NonTeachingStaff 实体类如下所示:package com.jc2182.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 文件包含数据库的配置信息和实体类的注册信息。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.jc2182.eclipselink.entity.Staff</class> <class>com.jc2182.eclipselink.entity.NonTeachingStaff</class> <class>com.jc2182.eclipselink.entity.TeachingStaff</class> <properties> <property name = "javax.persistence.jdbc.url" value = "jdbc:mysql://localhost: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.jc2182.eclipselink.service’.创建一个名为的类 SaveClient.java在给定的包下存储 Staff、TeachingStaff 和 NonTeachingStaff 类字段。SaveClient 类如下所示:package com.jc2182.eclipselink.service; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import com.jc2182.eclipselink.entity.NonTeachingStaff; import com.jc2182.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 工作台如下:这里创建了三个表,并且 Staff 表包含空记录。的结果 TeachingStaff 以表格形式显示如下:Sid Qualification Sname Subjectexpertise 1 MSC MED Gopal Maths 2 BSC BED Manisha English 上表TeachingStaff 包含Staff 和TeachingStaff 实体的字段。的结果 NonTeachingStaff 以表格形式显示如下:Sid Areaexpertise Sname 3 Accounts Satish 4 Office Admin Krishna 上表 NonTeachingStaff 包含 Staff 和 NonTeachingStaff 实体的字段。