Jump to: navigation, search

Difference between revisions of "EclipseLink/UserGuide/JPA/Basic JPA Development/Entities/Inheritance"

Line 22: Line 22:
 
JPA defines three inheritance strategies <code>SINGLE_TABLE</code>, <code>JOINED</code>, and <code>TABLE_PER_CLASS</code>.  By default the <code>SINGLE_TABLE</code> strategy is used and all of the subclasses are persisted in a single table that contains all of the column of all of the subclasses.  In addition a discriminator column named <code>DTYPE</code> is required in the table to store the class type.
 
JPA defines three inheritance strategies <code>SINGLE_TABLE</code>, <code>JOINED</code>, and <code>TABLE_PER_CLASS</code>.  By default the <code>SINGLE_TABLE</code> strategy is used and all of the subclasses are persisted in a single table that contains all of the column of all of the subclasses.  In addition a discriminator column named <code>DTYPE</code> is required in the table to store the class type.
  
By default the secondary table is joined to the primary table's id columns. This assumes that the secondary table has the same id columns defined with the same name.
+
The <tt>@Inheritance</tt> annotation has the following attributes:
If the secondary table uses different names for the id columns, then a set or <tt>@PrimaryKeyJoinColumn</tt>s must be provided. <tt>@PrimaryKeyJoinColumn</tt> can also be used for <tt>JOINED</tt> inheritance to specify how the child table is joined to the parent table. <tt>@PrimaryKeyJoinColumn</tt> still requires that the secondary table have all of the id columns of the primary table, for more advanced multiple table joins see [[#Advanced Multiple Table Configuration|Advanced Multiple Table Configuration]].
+
* <tt>strategy</tt> – By default, the EclipseLink persistence provider assumes that all the classes in a hierarchy are mapped to a single table differentiated by the discriminator value (see [[#@DiscriminatorValue|@DiscriminatorValue]]) in the table's discriminator column (see [[#@DiscriminatorColumn|@DiscriminatorColumn]]): <tt>InheritanceType.SINGLE_TABLE</tt>.<br>If this is not appropriate for your application or if you must match an existing data model, set <tt>strategy</tt> to the desired <tt>InheritanceType</tt> enumerated type:
 +
** <tt>SINGLE_TABLE</tt> – all the classes in a hierarchy are mapped to a single table. The table has a discriminator column ([[#@DiscriminatorColumn|@DiscriminatorColumn]]) whose value ([[#@DiscriminatorValue|@DiscriminatorValue]]) identifies the specific subclass to which the instance that is represented by the row belongs.<br><table class="Note oac_no_warn" width="80%" border="1" frame="hsides" rules="groups" cellpadding="3" frame="hsides" rules="groups"><tr><td>'''Note:''' This option provides the best support for both polymorphic relationships between entities and queries that range over the class hierarchy. The disadvantages of this option include the need to make nullable columns that should be <tt>NOT NULL</tt>.</td></tr></table><br>For more information, see Section 2.1.10.1 "Single Table per Class Hierarchy Strategy" of the [http://jcp.org/en/jsr/detail?id=220 JPA Specification].
 +
** <tt>TABLE_PER_CLASS</tt> – each class is mapped to a separate table. All properties of the class, including inherited properties, are mapped to columns of the table for the class.
 +
** <tt>JOINED</tt> the root of the class hierarchy is represented by a single table and each subclass is represented by a separate table. Each subclass table contains only those fields that are specific to the subclass (not inherited from its superclass) and primary key columns that serve as foreign keys to the primary keys of the superclass table.
  
{{EclipseLink_AttributeTable
+
{{EclipseLink_Spec|section=Section 2.1.9 "Inheritance"}}
|caption=@Inheritance Attributes
+
{{EclipseLink_Spec|section=Section 9.1.29 "Inheritance Annotation"}}
|content=<tr>
+
<td>'''<tt>name</tt>'''</td>
+
<td>The name of the table
+
<td></td>
+
<td>Yes</td>
+
</tr>
+
<tr>
+
<td>'''<tt>catalog</tt>'''</td>
+
<td>A <tt>String</tt> catalog name.
+
<td>Default catalog for database</td>
+
<td>No</td>
+
</tr>
+
<tr>
+
<td>'''<tt>schema</tt>'''</td>
+
<td>The <tt>String</tt> name of the schema.</td>
+
<td>Default schema of the database</td>
+
<td>No</td>
+
</tr>
+
<tr>
+
<td>'''<tt>uniqueConstraints</tt>'''</td>
+
<td></td>
+
<td>No additional constraints</td>
+
<td>No</td>
+
</tr>
+
}}
+
 
+
{{EclipseLink_Spec|section=Section 11.1.xx "Inheritance Annotation"}}
+
  
 
{{EclipseLink_AttributeTable
 
{{EclipseLink_AttributeTable

Revision as of 14:11, 21 June 2011

EclipseLink JPA

@Inheritance

You can use the @Inheritance annotation or <inheritance> XML element to configure how entities with inheritance are persisted. JPA defines three inheritance strategies SINGLE_TABLE, JOINED, and TABLE_PER_CLASS. By default the SINGLE_TABLE strategy is used and all of the subclasses are persisted in a single table that contains all of the column of all of the subclasses. In addition a discriminator column named DTYPE is required in the table to store the class type.

The @Inheritance annotation has the following attributes:

  • strategy – By default, the EclipseLink persistence provider assumes that all the classes in a hierarchy are mapped to a single table differentiated by the discriminator value (see @DiscriminatorValue) in the table's discriminator column (see @DiscriminatorColumn): InheritanceType.SINGLE_TABLE.
    If this is not appropriate for your application or if you must match an existing data model, set strategy to the desired InheritanceType enumerated type:
    • SINGLE_TABLE – all the classes in a hierarchy are mapped to a single table. The table has a discriminator column (@DiscriminatorColumn) whose value (@DiscriminatorValue) identifies the specific subclass to which the instance that is represented by the row belongs.
      Note: This option provides the best support for both polymorphic relationships between entities and queries that range over the class hierarchy. The disadvantages of this option include the need to make nullable columns that should be NOT NULL.

      For more information, see Section 2.1.10.1 "Single Table per Class Hierarchy Strategy" of the JPA Specification.
    • TABLE_PER_CLASS – each class is mapped to a separate table. All properties of the class, including inherited properties, are mapped to columns of the table for the class.
    • JOINED – the root of the class hierarchy is represented by a single table and each subclass is represented by a separate table. Each subclass table contains only those fields that are specific to the subclass (not inherited from its superclass) and primary key columns that serve as foreign keys to the primary keys of the superclass table.
Elug javaspec icon.gif

For more information, see Section 2.1.9 "Inheritance" in the JPA Specification.

Elug javaspec icon.gif

For more information, see Section 9.1.29 "Inheritance Annotation" in the JPA Specification.

@DiscriminatorColumn Attributes
Attribute Description Default Required?
name The name foreign key column in the secondary table that references the id column in the primary table id column No
referencedColumnName A name of the id column in the primary table that is being referenced. This is only required for composite ids. id column No
columnDefinition Optional column description for use with DDL generation. No
Elug javaspec icon.gif

For more information, see Section 11.1.xx "DiscriminatorColumn Annotation" in the JPA Specification.

The following example shows how to use this annotation to specify the table for Employee.

Example: Using @Inheritance
@Entity
@Table(name="EMP")
@SecondaryTable(name="SALARY")
public class Employee implements Serializable {
    ...
    @Id
    public Long getId() {
        return id;
    }
    ...
}
Example: Using <inheritance>
<entity class="Employee">
    <table name="EMP"/>
    <secondary-table name="SALARY"/>
    <attributes>
        <id name="id"/>
        ...
    </attributes>
</entity>


Advanced Inheritance Configuration

JPA requires that secondary tables contain the id of the entity. EclipseLink allows for the multiple table join to be based on foreign keys, or on specific criteria.

To define a secondary table that is joined through a foreign key, the ClassDescriptor.addForeignKeyFieldNameForMultipleTable() API is used. This column name given to this API should be prefixed by its table name, this allows for foreign keys from any of the secondary tables to be used in the multiple table join. Note that all of the column values still need to be mapped at least once.

If the multiple table join is more complex, an EclipseLink Expression can be used to define the join. The Expression is set on the ClassDescriptor's query manager using the DescriptorQueryManager.setMultipleTableJoinExpression() API. It is even possible to define a join Expression that make use of an outer-join on certain databases.

In certain advanced cases multiple tables can be encapsulated using a database view. This allows for any table join to be define in SQL and for the entity to be simply mapped to the view. To map an entity to a view, just use the view name instead of the table name. If the view is not updateable, your database may support instead of triggers to allow updates.

Example: Using a DescriptorCustomizer to configure a secondary table joined through a foreign key
@Entity
@Table(name="EMP")
@SecondaryTable(name="EMP_INFO")
@Customizer(EmployeeCustomizer.class)
public class Employee implements Serializable {
    @Id
    private Long id;
    @Basic
    @Column(name="ID", table="EMP_INFO")
    private String infoId;
    ...
}
public class EmployeeCustomizer implements DescriptorCustomizer {
    public void customize(ClassDescriptor descriptor) {
        descriptor.getAdditionalTablePrimaryKeyFields().clear();
        descriptor.getMultipleTableForeignKeys()().clear();
        descriptor.addForeignKeyFieldNameForMultipleTable("EMP.INFO_ID", "EMP_INFO.ID");
    }
}
Example: Using a DescriptorCustomizer to configure a secondary table joined through an Expression
@Entity
@Table(name="EMP")
@SecondaryTable(name="EMP_INFO")
@Customizer(EmployeeCustomizer.class)
public class Employee implements Serializable {
    @Id
    private Long id;
    @Basic
    @Column(name="ID", table="EMP_INFO")
    private String infoId;
    ...
}
public class EmployeeCustomizer implements DescriptorCustomizer {
    public void customize(ClassDescriptor descriptor) {
        ExpressionBuilder emp = new ExpressionBuilder();
        Expression join = emp.getField("EMP.INFO_ID").equal(emp.getField("EMP_INFO.ID").and(emp.getField("EMP_INFO.ARCHIVE").equal(false));
        descriptor.getQueryManager().setMultipleTableJoinExpression(join);
    }
}

Eclipselink-logo.gif
Version: 2.2.0 DRAFT
Other versions...