6. Inheritance Mapping

6.1. Mapped Superclasses

A mapped superclass is an abstract or concrete class that provides persistent entity state and mapping information for its subclasses, but which is not itself an entity. Typically, the purpose of such a mapped superclass is to define state and mapping information that is common to multiple entity classes.

マップされたスーパークラスは、永続的なエンティティの状態とそのサブクラスのマッピング情報を提供する抽象クラスまたは具象クラスですが、それ自体はエンティティではありません。通常、このようなマップされたスーパークラスの目的は、複数のエンティティ クラスに共通の状態とマッピング情報を定義することです。

Mapped superclasses, just as regular, non-mapped classes, can appear in the middle of an otherwise mapped inheritance hierarchy (through Single Table Inheritance or Class Table Inheritance).

マップされたスーパークラスは、通常のマップされていないクラスと同様に、(単一テーブルの継承またはクラス テーブルの継承を介して) マップされた継承階層の中間に出現する可能性があります。

Note

ノート

A mapped superclass cannot be an entity, it is not query-able and persistent relationships defined by a mapped superclass must be unidirectional (with an owning side only). This means that One-To-Many associations are not possible on a mapped superclass at all. Furthermore Many-To-Many associations are only possible if the mapped superclass is only used in exactly one entity at the moment. For further support of inheritance, the single or joined table inheritance features have to be used.

マップされたスーパークラスはエンティティにすることはできず、クエリ可能ではなく、マップされたスーパークラスによって定義される永続的な関係は一方向 (所有側のみ) でなければなりません。これは、マッピングされたスーパークラスでは一対多の関連付けがまったくできないことを意味します。または、結合されたテーブルの継承機能を使用する必要があります。

Example:

例:

<?php
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\OneToOne;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\MappedSuperclass;
use Doctrine\ORM\Mapping\Entity;

#[MappedSuperclass]
class Person
{
    #[Column(type: 'integer')]
    protected int $mapped1;
    #[Column(type: 'string')]
    protected string $mapped2;
    #[OneToOne(targetEntity: Toothbrush::class)]
    #[JoinColumn(name: 'toothbrush_id', referencedColumnName: 'id')]
    protected Toothbrush|null $toothbrush = null;

    // ... more fields and methods
}

#[Entity]
class Employee extends Person
{
    #[Id, Column(type: 'integer')]
    private int|null $id = null;
    #[Column(type: 'string')]
    private string $name;

    // ... more fields and methods
}

#[Entity]
class Toothbrush
{
    #[Id, Column(type: 'integer')]
    private int|null $id = null;

    // ... more fields and methods
}

The DDL for the corresponding database schema would look something like this (this is for SQLite):

対応するデータベース スキーマの DDL は次のようになります (これは SQLite 用です)。

CREATE TABLE EntitySubClass (mapped1 INTEGER NOT NULL, mapped2 TEXT NOT NULL, id INTEGER NOT NULL, name TEXT NOT NULL, related1_id INTEGER DEFAULT NULL, PRIMARY KEY(id))

As you can see from this DDL snippet, there is only a single table for the entity subclass. All the mappings from the mapped superclass were inherited to the subclass as if they had been defined on that class directly.

この DDL スニペットからわかるように、エンティティ サブクラスのテーブルは 1 つだけです。マップされたスーパークラスからのすべてのマッピングは、そのクラスで直接定義されているかのように、サブクラスに継承されました。

6.2. Single Table Inheritance

Single Table Inheritance is an inheritance mapping strategy where all classes of a hierarchy are mapped to a single database table. In order to distinguish which row represents which type in the hierarchy a so-called discriminator column is used.

単一テーブルの継承は、階層のすべてのクラスが単一のデータベース テーブルにマップされる継承マッピング戦略です。どの行が階層内のどのタイプを表しているかを区別するために、いわゆる識別子列が使用されます。

Example:

例:

Things to note:

注意事項:

  • The #[InheritanceType] and #[DiscriminatorColumn] must be

    #[InheritanceType] と #[DiscriminatorColumn] は、

specified on the topmost class that is part of the mapped entity hierarchy.

マップされたエンティティ階層の一部である最上位クラスで指定されます。

  • The #[DiscriminatorMap] specifies which values of the discriminator column identify a row as being of a certain type. In the case above a value of “person” identifies a row as being of type Person and “employee” identifies a row as being of type Employee.

    #[DiscriminatorMap] は、discriminator 列のどの値が行を特定のタイプとして識別するかを指定します。上記の例では、"person" の値は行を Person 型として識別し、"employee" は行を Employee 型として識別します。

  • All entity classes that is part of the mapped entity hierarchy (including the topmost class) should be specified in the #[DiscriminatorMap]. In the case above Person class included.

    マップされたエンティティ階層の一部であるすべてのエンティティ クラス (最上位のクラスを含む) は、#[DiscriminatorMap] で指定する必要があります。上記の場合 Person クラスが含まれます。

  • The names of the classes in the discriminator map do not need to be fully qualified if the classes are contained in the same namespace as the entity class on which the discriminator map is applied.

    ディスクリミネータ マップが適用されるエンティティ クラスと同じ名前空間にクラスが含まれている場合、ディスクリミネータ マップ内のクラスの名前を完全修飾する必要はありません。

  • If no discriminator map is provided, then the map is generated automatically. The automatically generated discriminator map contains the lowercase short name of each class as key.

    識別マップが提供されない場合、マップは自動的に生成されます。自動生成された識別子マップには、各クラスの小文字の短い名前がキーとして含まれています。

6.2.1. Design-time considerations

This mapping approach works well when the type hierarchy is fairly simple and stable. Adding a new type to the hierarchy and adding fields to existing supertypes simply involves adding new columns to the table, though in large deployments this may have an adverse impact on the index and column layout inside the database.

このマッピング アプローチは、型階層がかなり単純で安定している場合にうまく機能します。階層に新しいタイプを追加し、既存のスーパータイプにフィールドを追加するには、テーブルに新しい列を追加するだけですが、大規模な展開では、データベース内のインデックスと列のレイアウトに悪影響を与える可能性があります。

6.2.2. Performance impact

This strategy is very efficient for querying across all types in the hierarchy or for specific types. No table joins are required, only a WHERE clause listing the type identifiers. In particular, relationships involving types that employ this mapping strategy are very performing.

この戦略は、階層内のすべてのタイプまたは特定のタイプに対してクエリを実行する場合に非常に効率的です。テーブルの結合は不要で、タイプ識別子をリストする WHERE 句のみが必要です。特に、このマッピング戦略を使用する型を含む関係は非常に効果的です。

There is a general performance consideration with Single Table Inheritance: If the target-entity of a many-to-one or one-to-one association is an STI entity, it is preferable for performance reasons that it be a leaf entity in the inheritance hierarchy, (ie. have no subclasses). Otherwise Doctrine CANNOT create proxy instances of this entity and will ALWAYS load the entity eagerly.

Single TableInheritance には一般的なパフォーマンスの考慮事項があります。多対 1 または 1 対 1 の関連付けのターゲット エンティティが STI エンティティである場合、パフォーマンス上の理由から、継承階層のリーフ エンティティであることが望ましいです (サブクラスがない場合、Doctrine はこのエンティティのプロキシ インスタンスを作成できず、常にエンティティを積極的にロードします。

6.2.3. SQL Schema considerations

For Single-Table-Inheritance to work in scenarios where you are using either a legacy database schema or a self-written database schema you have to make sure that all columns that are not in the root entity but in any of the different sub-entities has to allow null values. Columns that have NOT NULL constraints have to be on the root entity of the single-table inheritance hierarchy.

レガシー データベース スキーマまたは自己記述データベース スキーマのいずれかを使用しているシナリオで単一テーブル継承が機能するには、ルート エンティティではなく、異なるサブエンティティのいずれかにあるすべての列が null を許可する必要があることを確認する必要があります。値。 NOT NULL 制約を持つ列は、単一テーブルの継承階層のルート エンティティにある必要があります。

6.3. Class Table Inheritance

Class Table Inheritance is an inheritance mapping strategy where each class in a hierarchy is mapped to several tables: its own table and the tables of all parent classes. The table of a child class is linked to the table of a parent class through a foreign key constraint. Doctrine ORM implements this strategy through the use of a discriminator column in the topmost table of the hierarchy because this is the easiest way to achieve polymorphic queries with Class Table Inheritance.

クラス テーブルの継承は、階層内の各クラスが複数のテーブル (独自のテーブルとすべての親クラスのテーブル) にマップされる継承マッピング戦略です。子クラスのテーブルは、外部キー制約を通じて親クラスのテーブルにリンクされています。 Doctrine ORM は、階層の最上位のテーブルにある識別子列を使用してこの戦略を実装します。これは、クラス テーブルの継承を使用してポリモーフィック クエリを実現する最も簡単な方法だからです。

Example:

例:

<?php
namespace MyProject\Model;

#[Entity]
#[InheritanceType('JOINED')]
#[DiscriminatorColumn(name: 'discr', type: 'string')]
#[DiscriminatorMap(['person' => Person::class, 'employee' => Employee::class])]
class Person
{
    // ...
}

#[Entity]
class Employee extends Person
{
    // ...
}

Things to note:

注意事項:

  • The #[InheritanceType], #[DiscriminatorColumn] and

    #[InheritanceType]、#[DiscriminatorColumn] および

#[DiscriminatorMap] must be specified on the topmost class that is part of the mapped entity hierarchy.

#[DiscriminatorMap] は、マップされたエンティティ階層の一部である最上位クラスで指定する必要があります。

  • The #[DiscriminatorMap] specifies which values of the discriminator column identify a row as being of which type. In the case above a value of “person” identifies a row as being of type Person and “employee” identifies a row as being of type Employee.

    #[DiscriminatorMap] は、discriminator 列のどの値が行をどのタイプとして識別するかを指定します。上記の例では、「person」の値は行を typePerson として識別し、「employee」は行を typeEmployee として識別します。

  • The names of the classes in the discriminator map do not need to be fully qualified if the classes are contained in the same namespace as the entity class on which the discriminator map is applied.

    ディスクリミネータ マップが適用されるエンティティ クラスと同じ名前空間にクラスが含まれている場合、ディスクリミネータ マップ内のクラスの名前を完全修飾する必要はありません。

  • If no discriminator map is provided, then the map is generated automatically. The automatically generated discriminator map contains the lowercase short name of each class as key.

    識別マップが提供されない場合、マップは自動的に生成されます。自動生成された識別子マップには、各クラスの小文字の短い名前がキーとして含まれています。

Note

ノート

When you do not use the SchemaTool to generate the required SQL you should know that deleting a class table inheritance makes use of the foreign key property ON DELETE CASCADE in all database implementations. A failure to implement this yourself will lead to dead rows in the database.

SchemaTool を使用して必要な SQL を生成しない場合は、クラス テーブルの継承を削除すると、すべてのデータベース実装で外部キー プロパティの ON DELETE CASCADE が使用されることを知っておく必要があります。これを自分で実装しないと、データベースにデッド ローが発生します。

6.3.1. Design-time considerations

Introducing a new type to the hierarchy, at any level, simply involves interjecting a new table into the schema. Subtypes of that type will automatically join with that new type at runtime. Similarly, modifying any entity type in the hierarchy by adding, modifying or removing fields affects only the immediate table mapped to that type. This mapping strategy provides the greatest flexibility at design time, since changes to any type are always limited to that type’s dedicated table.

任意のレベルで新しいタイプを階層に導入することは、単純に新しいテーブルをスキーマに挿入することを伴います。そのタイプのサブタイプは、実行時にその新しいタイプと自動的に結合します。同様に、フィールドを追加、変更、または削除して階層内のエンティティ タイプを変更すると、そのタイプにマッピングされた直接のテーブルのみに影響します。このマッピング戦略は、どのタイプへの変更も常にそのタイプの専用テーブルに制限されるため、設計時に最大の柔軟性を提供します。

6.3.2. Performance impact

This strategy inherently requires multiple JOIN operations to perform just about any query which can have a negative impact on performance, especially with large tables and/or large hierarchies. When partial objects are allowed, either globally or on the specific query, then querying for any type will not cause the tables of subtypes to be OUTER JOINed which can increase performance but the resulting partial objects will not fully load themselves on access of any subtype fields, so accessing fields of subtypes after such a query is not safe.

この戦略では、特に大規模なテーブルや大規模な階層で、パフォーマンスに悪影響を与える可能性があるほぼすべてのクエリを実行するために複数の JOIN 操作が本質的に必要です。グローバルまたは特定のクエリで部分オブジェクトが許可されている場合、どのタイプのクエリでもサブタイプのテーブルを OUTER JOIN にすることで、パフォーマンスを向上させることができますが、結果として得られる部分オブジェクトは、サブタイプ フィールドへのアクセス時に完全にロードされないため、そのようなクエリの後でサブタイプのフィールドにアクセスすることは安全ではありません。

There is a general performance consideration with Class Table Inheritance: If the target-entity of a many-to-one or one-to-one association is a CTI entity, it is preferable for performance reasons that it be a leaf entity in the inheritance hierarchy, (ie. have no subclasses). Otherwise Doctrine CANNOT create proxy instances of this entity and will ALWAYS load the entity eagerly.

クラス TableInheritance には一般的なパフォーマンスの考慮事項があります。多対 1 または 1 対 1 の関連付けのターゲット エンティティが CTI エンティティである場合、パフォーマンス上の理由から、継承階層のリーフ エンティティであることが望ましいです (サブクラスがない場合、Doctrine はこのエンティティのプロキシ インスタンスを作成できず、常にエンティティを積極的にロードします。

There is also another important performance consideration that it is NOT POSSIBLE to query for the base entity without any LEFT JOINs to the sub-types.

サブタイプへの LEFT JOIN なしでベース エンティティをクエリすることは不可能であるという、もう 1 つの重要なパフォーマンス上の考慮事項もあります。

6.3.3. SQL Schema considerations

For each entity in the Class-Table Inheritance hierarchy all the mapped fields have to be columns on the table of this entity. Additionally each child table has to have an id column that matches the id column definition on the root table (except for any sequence or auto-increment details). Furthermore each child table has to have a foreign key pointing from the id column to the root table id column and cascading on delete.

Class-Table Inheritance 階層内の各エンティティについて、マップされたすべてのフィールドは、このエンティティのテーブルの列である必要があります。さらに、各子テーブルには、ルート テーブルの ID 列定義と一致する ID 列が必要です (シーケンスまたは自動を除く)。増分の詳細)。さらに、各子テーブルには、id 列からルート テーブルの idcolumn を指し、削除時にカスケードする外部キーが必要です。

6.4. Overrides

Used to override a mapping for an entity field or relationship. Can only be applied to an entity that extends a mapped superclass or uses a trait to override a relationship or field mapping defined by the mapped superclass or trait.

エンティティ フィールドまたは関係のマッピングをオーバーライドするために使用されます。マッピングされたスーパークラスを拡張するエンティティ、または特性を使用してマッピングされたスーパークラスまたは特性によって定義された関係またはフィールド マッピングをオーバーライドするエンティティにのみ適用できます。

It is not possible to override attributes or associations in entity to entity inheritance scenarios, because this can cause unforseen edge case behavior and increases complexity in ORM internal classes.

エンティティ間の継承シナリオで属性または関連付けをオーバーライドすることはできません。これは、予期しないエッジ ケースの動作が発生し、ORM 内部クラスが複雑になる可能性があるためです。

6.4.1. Association Override

Override a mapping for an entity relationship.

エンティティ関係のマッピングをオーバーライドします。

Could be used by an entity that extends a mapped superclass to override a relationship mapping defined by the mapped superclass.

マッピングされたスーパークラスによって定義された関係マッピングをオーバーライドするために、マッピングされたスーパークラスを拡張するエンティティによって使用される可能性があります。

Example:

例:

Things to note:

注意事項:

  • The “association override” specifies the overrides base on the property name.

    「関連オーバーライド」は、プロパティ名に基づいてオーバーライドを指定します。

  • This feature is available for all kind of associations. (OneToOne, OneToMany, ManyToOne, ManyToMany)

    この機能は、あらゆる種類の関連付けで使用できます。 (OneToOne、OneToMany、ManyToOne、ManyToMany)

  • The association type CANNOT be changed.

    関連付けタイプは変更できません。

  • The override could redefine the joinTables or joinColumns depending on the association type.

    オーバーライドは、関連付けの種類に応じて、joinTables または joinColumns を再定義できます。

  • The override could redefine inversedBy to reference more than one extended entity.

    オーバーライドは、inversedBy を再定義して、複数の拡張エンティティを参照できます。

  • The override could redefine fetch to modify the fetch strategy of the extended entity.

    オーバーライドは、フェッチを再定義して、拡張エンティティのフェッチ戦略を変更できます。

6.4.2. Attribute Override

Override the mapping of a field.

フィールドのマッピングをオーバーライドします。

Could be used by an entity that extends a mapped superclass to override a field mapping defined by the mapped superclass.

マッピングされたスーパークラスによって定義されたフィールド マッピングをオーバーライドするために、マッピングされたスーパークラスを拡張するエンティティによって使用される可能性があります。

Things to note:

注意事項:

  • The “attribute override” specifies the overrides base on the property name.

    「属性オーバーライド」は、プロパティ名に基づいてオーバーライドを指定します。

  • The column type CANNOT be changed. If the column type is not equal you get a MappingException

    列タイプは変更できません。列の型が等しくない場合は、MappingException が発生します

  • The override can redefine all the attributes except the type.

    オーバーライドは、タイプを除くすべての属性を再定義できます。

6.5. Query the Type

It may happen that the entities of a special type should be queried. Because there is no direct access to the discriminator column, Doctrine provides the INSTANCE OF construct.

特殊なタイプのエンティティを照会する必要がある場合があります。 discriminator 列に直接アクセスできないため、Doctrine は INSTANCE OF 構文を提供します。

The following example shows how to use INSTANCE OF. There is a three level hierarchy with a base entity NaturalPerson which is extended by Staff which in turn is extended by Technician.

次の例は、INSTANCE OF の使用方法を示しています。基本エンティティ NaturalPerson を含む 3 レベルの階層があり、Staff によって拡張され、Staff は Technician によって拡張されます。

Querying for the staffs without getting any technicians can be achieved by this DQL:

技術者を取得せずにスタッフを照会するには、次の DQL を使用します。

<?php
$query = $em->createQuery("SELECT staff FROM MyProject\Model\Staff staff WHERE staff NOT INSTANCE OF MyProject\Model\Technician");
$staffs = $query->getResult();

Table Of Contents

Previous topic

5. Association Mapping

5. アソシエーション マッピング

Next topic

7. Working with Objects

7. オブジェクトの操作

This Page

Fork me on GitHub