説明

前のレッスンでは、Hibernate が特別な DTYPE VARCHAR 列を使用してエンティティ クラスの名前を保存することを見ました。このような列は、ディスクリミネーターと呼ばれます。これは、データベース内の特定の行に対してどのクラスを作成するかを明確に決定するために使用されます。

@DiscriminatorColumnアノテーションを使用してこの列を操作できます。例:

@DiscriminatorColumn(name="column_name",   discriminatorType = DiscriminatorType.INTEGER)

JPA 仕様によれば、識別子は次の型を持つことができます。

  • チャー
  • 整数

ただし、Hibernate を使用すると、このリストを少し拡張できます。次の Java タイプをサポートします: String、char、int、byte、short、boolean。

INTEGER 型を使用する場合、その中で Entity クラスの名前をエンコードするにはどうすればよいでしょうか? このために、別のアノテーション@DiscriminatorValueが使用されます。

例を見てみましょう:

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="user_type",   discriminatorType = DiscriminatorType.INTEGER)
@Entity
class User {
  int id;
  String name;
  LocalDate birthday;
}
@Entity
@DiscriminatorValue("1")
class Employee extends User {
 	String occupation;
 	int salary;
 	LocalDate join;
}
@Entity
@DiscriminatorValue("2")
class Client extends User {
   String address;
}

上の例では、識別子が数値を格納する user_type カラムを使用することを Hibernate に伝えました。値 1 が格納されている場合は行タイプが Employee であることを意味し、値 2 が格納されている場合は行タイプが Client であることを意味します。シンプルで美しい。

@DiscriminatorValue

しかし、それだけではありません。識別子が NULL の場合に文字列の型を解釈する方法を Hibernate に指示できます。

実はとてもシンプルなのです。@DiscriminatorValueアノテーションに null 値を指定します。たとえば、次のようになります。

@DiscriminatorValue("null")

クラスの例:

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="user_type",   discriminatorType = DiscriminatorType.INTEGER)
@DiscriminatorValue("null")
@Entity
class User {
  int id;
  String name;
  LocalDate birthday;
}

Hibernate には、user_type 列に NULL が含まれるテーブル行はすべて User 型のオブジェクトとして解釈されるように指示しました。

しかし、それだけではありません。@DiscriminatorValue アノテーションには別の興味深い値があります。

これは次のとおりです。

@DiscriminatorValue("not null")

クラスの例:

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="user_type",   discriminatorType = DiscriminatorType.INTEGER)
@DiscriminatorValue("not null")
@Entity
class User {
  int id;
  String name;
  LocalDate birthday;
}

このアノテーションを使用して、user_type カラムに NULL 以外の値を持つテーブル行はすべて User 型のオブジェクトとして解釈されるように Hibernate に指示しました。ただし、これは、必要な数が明示的に指定されたクラスが見つからない場合にのみ当てはまります。

これは、識別子のさまざまな値に対してどのように機能するかです。

  • 0 - ユーザー型のオブジェクトを作成します
  • 1 -従業員タイプのオブジェクトを作成します
  • 2 -クライアントタイプのオブジェクトを作成します
  • 3 - ユーザー型のオブジェクトを作成します
  • 4 - ユーザー型のオブジェクトを作成します

@DiscriminatorFormula

しかし、それだけではありません。識別子には、 @DiscriminatorValueアノテーションの値を計算する整数式を指定できます。

これには特別なアノテーションがあり、@DiscriminatorFormulaと呼ばれます。

例:

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="user_type",   discriminatorType = DiscriminatorType.INTEGER)
@DiscriminatorFormula("case when ‘join’ is not null then 1 else 2 end")
@Entity
class User {
  int id;
  String name;
  LocalDate birthday;
}
@Entity
@DiscriminatorValue("1")
class Employee extends User {
 	String occupation;
 	int salary;
 	LocalDate join;
}
@Entity
@DiscriminatorValue("2")
class Client extends User {
   String address;
}

@DiscriminatorFormulaによって返された値は、 Hibernate によって@DiscriminatorValueアノテーションで指定された値と比較されます。これを使用すると、非常に複雑なシナリオを作成できます。

@DiscriminatorFormula(
           	"case when address is not null " +
           	"then 'Client' " +
           	"else (" +
           	"   case when occupation is not null " +
           	"   then 'Employee' " +
           	"   else 'Unknown' " +
           	"   end) " +
           	"end "
)