AI エージェント向け: ドキュメントインデックスは https://www.mongodb.com/ja-jp/docs/llms.txt で利用できます。すべてのページの markdown バージョンは、いずれかの URL パスに .md を追加することで利用できます。

エンティティ継承階層のマッピング

このガイドでは、Hibernate ORM拡張機能を使用してJavaクラス階層をMongoDBコレクションにマッピングする方法を学びます。Javaサブクラスが親クラスを拡張し、そのフィールドを継承する場合、クラスは階層を形成します。Hibernate ORMは、拡張機能が階層内の各クラスをどのように保存するかを決定する継承戦略を提供します。選択する戦略によって、どのコレクションがデータを保持するか、および結果として得られるドキュメントの形状が決まります。

Hibernate ORM拡張機能は、以下の継承戦略をサポートしています。

  • 単一テーブル継承: Hibernate ORM拡張機能は、クラス階層全体を1つのコレクションに保存します。

  • マッピングされたスーパークラス: エンティティではないスーパークラスは、独自のコレクションを持たずに、各サブクラスにフィールドを提供します。

この拡張機能は、JOINED および TABLE_PER_CLASS の継承戦略をサポートしていません。詳細については、このガイドの「サポートされていない戦略」セクションをご覧ください。

単一テーブル継承戦略では、フレームワークは階層内のすべてのクラスを同じMongoDBコレクション内に保存します。この戦略を使用するには、階層の最上位の親クラスであるルートエンティティに@Inheritance(strategy = InheritanceType.SINGLE_TABLE)アノテーションを適用します。

コレクションには複数のクラスにマッピングされるドキュメントが格納されるため、拡張機能は各ドキュメントがマッピングされるクラスをレコードする必要があります。オブジェクトを保存すると、拡張機能はこの情報をdiscriminatorフィールドに保存します。コレクションをクエリすると、拡張機能はdiscriminator値を読み取り、インスタンス化するクラスを決定します。

差別子フィールドを指定するには、ルート エンティティに @DiscriminatorColumn アノテーションを適用します。クラスの識別子の値を設定するには、クラスに @DiscriminatorValue アノテーションを適用します。

次の例では、Movie階層をmoviesコレクションにマッピングします。ActorサブクラスとDirectorサブクラスはどちらもMovieからnameフィールドを継承しますが、各サブクラスは独自のフィールドも追加します。各ドキュメントは、role識別子フィールドに"actor"または"director"のいずれかを保存します。

@Entity@Table(name = "movies")@Inheritance(strategy = InheritanceType.SINGLE_TABLE)@DiscriminatorColumn(name = "role")public abstract class Movie { @Id @ObjectIdGenerator private ObjectId id; private String name; // Getter and setter methods } @Entity@DiscriminatorValue("actor")public class Actor extends Movie { private List<String> awards; // Getter and setter methods } @Entity@DiscriminatorValue("director")public class Director extends Movie { private String studio; // Getter and setter methods }

persist() インスタンスまたは Actor インスタンスで Director メソッドを呼び出すと、拡張機能は対応するドキュメントを movies コレクションに挿入します。各ドキュメントには、そのクラスが定義するフィールドと、そのクラスの識別子値が含まれています。

{ "_id": ObjectId("..."), "role": "actor", "name": "Andrew Garfield", "awards": ["Golden Globe Award"] }{ "_id": ObjectId("..."), "role": "director", "name": "Greta Gerwig", "studio": "Warner Bros." }

上記の例では、デフォルトの識別子タイプであるstring識別子を使用しています。このタイプを変更するには、@DiscriminatorColumnアノテーションのdiscriminatorType要素を設定します。この要素をDiscriminatorType.CHARに設定すると識別子が文字として保存され、DiscriminatorType.INTEGERに設定すると識別子が整数として保存されます。

重要

文字型および整数型の判別子には明示的な値が必要

Hibernateでは、文字型または整数型のディスクリミネーターの場合、クラスのディスクリミネーター値はデフォルトでクラス名になりません。discriminatorTypeをDiscriminatorType.CHARまたはDiscriminatorType.INTEGERに設定する場合、ルートエンティティを直接インスタンス化しない場合でも、ルートエンティティと各サブクラスに@DiscriminatorValueアノテーションを追加する必要があります。

moviesコレクションには、Movie階層内のすべてのクラスのドキュメントが含まれています。これらのクラスのいずれかをクエリすると、Hibernate ORM拡張機能がディスクリミネーターフィールドでフィルター処理を行うため、クエリはそのクラスのドキュメントのみを返します。このフィルターは、クエリするクラスによって異なります。

  • サブクラスをクエリすると、拡張機能は識別子がそのサブクラスの識別子値と一致するドキュメントを照合します。前の例で Actor をクエリすると、role が "actor" であるドキュメントのみが一致します。

  • ルートクラスをクエリする場合、拡張機能はフィルターを追加しません。このクエリはコレクション内のすべてのドキュメントを読み取り、各ドキュメントの識別子値を使用して正しいクラスのオブジェクトを返します。前の例で Movie をクエリすると、Actor ドキュメントと Director ドキュメントの両方が返されます。コレクションに、その識別子値が階層内のクラスにマップされないドキュメントが含まれている場合、クエリは HibernateException をスローします。

エンティティのクエリについて詳しく学ぶには、「クエリの指定」ガイドを参照してください。

Mapped superclassは、それ自体がエンティティになることなく、サブクラスとフィールドマッピングを共有します。mapped superclassを作成するには、@MappedSuperclassアノテーションをスーパークラスに適用します。mapped superclassはエンティティではないため、Hibernate ORM拡張機能はそれに対するコレクションを作成せず、直接クエリを実行することもできません。

マッピングされたスーパークラスを拡張する各サブクラスは、独自のコレクションにマッピングされます。各ドキュメントにおいて、この拡張機能は継承されたフィールドとサブクラス独自のフィールドをトップレベルのフィールドとして保存します。この拡張機能は、継承されたフィールドをネストしたり、個別に保存したりすることはありません。

次の例では、Genre エンティティと Language エンティティの識別子と名前のマッピングを提供する MovieDetails マップドスーパークラスを定義します。

@MappedSuperclasspublic abstract class MovieDetails { @Id @ObjectIdGenerator private ObjectId id; private String name; // Getter and setter methods } @Entity@Table(name = "genres")public class Genre extends MovieDetails { private String description; // Getter and setter methods } @Entity@Table(name = "languages")public class Language extends MovieDetails { private String code; // Getter and setter methods }

前の例では、@MappedSuperclass アノテーションを使用することで、MovieDetails はエンティティになることなく id と name のマッピングを定義できます。次に、Genre と Language の @Entity および @Table アノテーションによって、各サブクラスが独自のコレクションにマッピングされます。

その結果、拡張機能は MovieDetails のコレクションを作成しません。代わりに、拡張機能は Genre ドキュメントを genres コレクションに、Language ドキュメントを languages コレクションに保存します。各ドキュメントには、対応するクラスで定義されているフィールドに加えて、MovieDetails がマップする _id フィールドと name フィールドが含まれています。

{ "_id": ObjectId("..."), "description": "Serious, narrative-driven stories.", "name": "Drama" }{ "_id": ObjectId("..."), "code": "en", "name": "English" }

Hibernate ORM拡張機能は、単一のクラス階層を複数のテーブルに保存する以下のHibernate ORM継承戦略をサポートしていません。

  • InheritanceType.JOINED各クラスを独自のテーブルに保存し、テーブルを結合してインスタンスを再構築します

  • InheritanceType.TABLE_PER_CLASS各具象クラスを独自のテーブルに保存し、テーブルを結合して階層をクエリします

前述のいずれかの戦略でクラスをマッピングした場合、拡張機能は FeatureNotSupportedException をスローします。

重要

スタートアップ時にエラーが発生する

Hibernate ORM拡張機能は、SessionFactoryインスタンスをビルドする際に継承戦略を検証します。サポートされていない戦略を使用するアプリケーションは起動できません。

エンティティの作成と埋め込みデータのマッピングの詳細については、「コレクションを表すエンティティの作成」ガイドを参照してください。

エンティティを使用してデータベース操作を実行する方法を学ぶには、「CRUD 操作の実行」および「クエリの指定」ガイドを参照してください。

Hibernate ORM拡張機能がサポートする機能のリストを表示するには、互換性ページを参照してください。

Hibernate ORM 継承戦略についてさらに学ぶには、 Hibernate ORM ドキュメントの 継承 を参照してください。