Jump to: navigation, search

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

Line 32: Line 32:
 
{{EclipseLink_Note|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>.}}<br>
 
{{EclipseLink_Note|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>.}}<br>
 
<li> <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.
 
<li> <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.
{{EclipseLink_Note|note=This option has several limitations when querying or having relationships to the root or branch classes.}}
+
{{EclipseLink_Note|note=This option has several limitations when querying or having relationships to the root or branch classes.  Joins to root or branch classes are not supported.}}
 
<li> <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.  The join from the primary table to the subclass table can be configured using the <code>@PrimaryKeyJoinColumn</code>, see [[EclipseLink/UserGuide/JPA/Basic JPA Development/Entities/SecondaryTable|SecondaryTable]] for more info.
 
<li> <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.  The join from the primary table to the subclass table can be configured using the <code>@PrimaryKeyJoinColumn</code>, see [[EclipseLink/UserGuide/JPA/Basic JPA Development/Entities/SecondaryTable|SecondaryTable]] for more info.
 
</ul></ul>
 
</ul></ul>
Line 39: Line 39:
 
{{EclipseLink_Spec|section=Section 9.1.29 "Inheritance Annotation"}}
 
{{EclipseLink_Spec|section=Section 9.1.29 "Inheritance Annotation"}}
  
=@DiscriminatorColumn=
+
===@DiscriminatorColumn===
You can use the <tt>@DiscriminatorColumn</tt> annotation or <code><nowiki><discriminator-column></nowiki></code> XML element to configure the name or type of the inheritance discriminator column.  The discriminator column is required for <code>SINGLE_TABLE</code> and <code>JOINED</code> inheritance and stores the associated entity type for the row.  JPA only allows String or Integer values for discriminators.  Through the EclipseLink API, it is possible to use other discriminator types, and it is possible to not have a discriminator, or use custom discriminator, see [[#Advanced Inheritance Configuration|Advanced Inheritance Configuration]].
+
You can use the <tt>@DiscriminatorColumn</tt> annotation or <code><nowiki><discriminator-column></nowiki></code> XML element to configure the name or type of the inheritance discriminator column.  The discriminator column is required for <code>SINGLE_TABLE</code> and <code>JOINED</code> inheritance and stores the associated entity type for the row.  The default name for the discriminator column is <code>DTYPE</code>.  JPA only allows String or Integer values for discriminators.  Through the EclipseLink API, it is possible to use other discriminator types, and it is possible to not have a discriminator, or use custom discriminator, see [[#Advanced Inheritance Configuration|Advanced Inheritance Configuration]].
  
 
{{EclipseLink_AttributeTable
 
{{EclipseLink_AttributeTable
Line 63: Line 63:
 
</tr>
 
</tr>
 
}}
 
}}
 +
{{EclipseLink_Spec|section=Section 11.1.xx "DiscriminatorColumn Annotation"}}
  
=@DiscriminatorValue=
+
===@DiscriminatorValue===
 
You can use the <tt>@DiscriminatorValue</tt> annotation or <code><nowiki><discriminator-value></nowiki></code> XML element to configure the value of the inheritance discriminator.  The discriminator value can be specified in each non-abstract class in the inheritance hierarchy.  By default the discriminator value is the entity's name, which defaults to its unprefixed class name.  The discriminator value is always specified as a String, but is converted to the discriminator column type.
 
You can use the <tt>@DiscriminatorValue</tt> annotation or <code><nowiki><discriminator-value></nowiki></code> XML element to configure the value of the inheritance discriminator.  The discriminator value can be specified in each non-abstract class in the inheritance hierarchy.  By default the discriminator value is the entity's name, which defaults to its unprefixed class name.  The discriminator value is always specified as a String, but is converted to the discriminator column type.
  
{{EclipseLink_Spec|section=Section 11.1.xx "DiscriminatorColumn Annotation"}}
 
  
 
The following example shows how to use this annotation to specify the table for <code>Employee</code>.
 
The following example shows how to use this annotation to specify the table for <code>Employee</code>.

Revision as of 09:57, 22 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.

      Elug note icon.png

      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.


    • 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.

      Elug note icon.png

      Note: This option has several limitations when querying or having relationships to the root or branch classes. Joins to root or branch classes are not supported.

    • 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. The join from the primary table to the subclass table can be configured using the @PrimaryKeyJoinColumn, see SecondaryTable for more info.
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

You can use the @DiscriminatorColumn annotation or <discriminator-column> XML element to configure the name or type of the inheritance discriminator column. The discriminator column is required for SINGLE_TABLE and JOINED inheritance and stores the associated entity type for the row. The default name for the discriminator column is DTYPE. JPA only allows String or Integer values for discriminators. Through the EclipseLink API, it is possible to use other discriminator types, and it is possible to not have a discriminator, or use custom discriminator, see Advanced Inheritance Configuration.

@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.

@DiscriminatorValue

You can use the @DiscriminatorValue annotation or <discriminator-value> XML element to configure the value of the inheritance discriminator. The discriminator value can be specified in each non-abstract class in the inheritance hierarchy. By default the discriminator value is the entity's name, which defaults to its unprefixed class name. The discriminator value is always specified as a String, but is converted to the discriminator column type.


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...