S2JDBC - エンティティ

エンティティの定義の仕方を説明します。ここでいっているエンティティとは、 データベースに永続化されるものだと考えてください。

注意点

エンティティ用のアノテーションは、JPAのものをそのまま利用していますが、 すべてのアノテーションや要素をサポートしているわけではありません。 ここに取り上げられているもののみサポートされているとお考えください。

エンティティにするためには、 @Entity を必ず指定する必要があります。

name 要素でエンティティ名を指定することができます。 次の例では、 Emp というエンティティ名を指定しています。

name 要素を指定しなかった場合、エンティティのクラス名からパッケージ名を除いた部分が、 デフォルトのエンティティ名になります。例えば、クラス名が examples.entity.Employee の場合、デフォルトのエンティティ名は、 Employee になります。

テーブル情報を指定するには、 @Table を使います。

name 要素でテーブル名を指定することができます。 指定しなかった場合、テーブル名はエンティティ名と同じになります。エンティティ名が、 AaaBbb のようなキャメル記法の場合、テーブル名は、 AAA_BBB のように '_' 区切りだとみなされます。

このルールは、 convention.dicon で指定されている org.seasar.framework.convention.impl.PersistenceNamingConventionImpl の fromEntityNameToTableName() の実装を変えることで、カスタマイズすることができます。

次の例では、 EMP というテーブル名を指定しています。

schema 要素でスキーマを指定することができます。 指定した場合、自動生成されるSQLのテーブル名がスキーマ.テーブル名になります。

catalog 要素でカタログを指定することができます。 指定した場合、自動生成されるSQLのテーブル名がカタログ.テーブル名になります。 catalog 要素と schema 要素の両方を指定した場合、自動生成されるSQLのテーブル名はカタログ.スキーマ.テーブル名になります。

エンティティは @MappedSuperclass が指定されたクラスを継承できます。

@MappedSuperclass には、エンティティと同じように永続プロパティを定義できます。 定義された永続プロパティは、サブクラスの永続プロパティとみなされます。 スーパークラスとサブクラスでインスタンスフィールドの名前が重複しないように定義してください。

エンティティは @MappedSuperclass が指定されていないクラスも継承できます。 しかし、この場合、スーパークラスのプロパティはサブクラスの永続プロパティとみなされません。

エンティティが他のエンティティを継承することはサポートされていません。

関連 および 永続化対象外 を除いたプロパティとして利用可能な型は次のとおりです。

プリミティブ型
  • boolean
  • char
  • byte
  • short
  • int
  • long
  • float
  • double
ラッパー型
  • Boolean
  • Character
  • Byte
  • Short
  • Integer
  • Long
  • Float
  • Double
文字列型
  • java.lang.String

※ ラージオブジェクト にすることができます。

数値型
  • java.math.BigDecimal
  • java.math.BigInteger
列挙型
  • java.lang.Enumのサブクラス
日付・時刻型
  • java.util.Date
  • java.util.Calendar
  • java.sql.Date
  • java.sql.Time
  • java.sql.Timestamp

※ java.util.Date および java.util.Calendar 型のプロパティには 時制 の指定が必須です.

バイト列型
  • byte[]

※ ラージオブジェクト にすることができます。

シリアライズ可能型
  • java.io.Serializable

※ ラージオブジェクト にすることができます。

カラム情報を指定するには、 @Column を使います。

name 要素でカラム名を指定することができます。 指定しなかった場合、カラム名はフィールド名と同じになります。フィールド名が、 aaaBbb のようなキャメル記法の場合、カラム名は、 AAA_BBB のように '_' 区切りだとみなされます。

このルールは、 convention.dicon で指定されている org.seasar.framework.convention.impl.PersistenceNamingConventionImpl の fromPropertyNameToColumnName() の実装を変えることで、カスタマイズすることができます。

デフォルトでは、プロパティ名とフィールド名は同じになりますが、 convention.dicon で指定されている org.seasar.framework.convention.impl.PersistenceNamingConventionImpl の fromFieldNameToPropertyName() の実装を変えることで、カスタマイズすることができます。

次の例では、 AB1234 というカラム名を指定しています。

insertable 要素で挿入可能かどうかを指定することができます。デフォルトは true です。 false の場合、挿入用のSQLにこのカラムは含まれません。 カラムにデフォルト値を適用したい場合は、 false にすると良いでしょう。

updatable 要素で更新可能かどうかを指定することができます。デフォルトは true です。 false の場合、更新用のSQLにこのカラムは含まれません。 カラムにデフォルト値を適用したい場合は、 false にすると良いでしょう。

識別子(主キー)であることを指定するには、 @Id を使います。

複合主キーの場合は、 @Id を複数つけます。

識別子は、アプリケーション側で生成することもできますが、 Seasar2に自動生成させることもできます。 自動生成させるには、 @GeneratedValue を使います。

自動生成のタイプは、 @GeneratedValue の strategy 要素で指定します。指定できるタイプのは次の4つです。

GenerationType.TABLE
テーブルを使います。
GenerationType.SEQUENCE
シーケンスを使います。
GenerationType.IDENTITY
データベース固有の識別子自動生成を使います。
GenerationType.AUTO (デフォルト)
データベースに応じて TABLE・SEQUENCE・IDENTITY のいずれかが選択されます。 IDENTITY が使える場合は IDENTITY に、 IDENTITY が使えなくて SEQUENCE が使える場合は SEQUENCE に、 IDENTITY も SEQUENCE も使えない場合は TABLE になります。

GenerationType.TABLE

GenerationType.TABLE は次のようにして使います。

上記のように指定した場合、あらかじめ、次のようなテーブルとデータを用意しておく必要があります。

ID_GENERATOR テーブルのPKカラムには、 <テーブル名>_<識別子のカラム名> を設定します。

テーブル名やカラム名をカスタマイズするには、次のように @TableGenerator アノテーションで指定します。

上記のような TableGenerator を定義した場合、あらかじめ、次のようなテーブルとデータを用意しておく必要があります。

GenerationType.SEQUENCE

GenerationType.SEQUENCE は次のようにして使います。

上記のように指定した場合、あらかじめ、次のようなシーケンスを用意しておく必要があります。

シーケンス名は、 <テーブル名>_<識別子のカラム名> となります。

シーケンス名をカスタマイズするには、次のように @SequenceGenerator アノテーションで指定します。

上記のような SequenceGenerator を定義した場合、 あらかじめ、次のようなシーケンスを用意しておく必要があります。

GenerationType.IDENTITY

GenerationType.IDENTITY は次のようにして使います。

GenerationType.IDENTITY を使う場合、識別子はデータベース固有の方法を使って自動生成されるようにしてください。

バージョンチェック用であることを指定するには、 @Version を使います。更新時に、エンティティの値とカラムの値が同一かどうかをチェックし、 同一ならカラムの値がインクリメントされて更新されます。同一でない場合、 javax.persistence.OptimisticLockException が発生します。

例えば、エンティティのバージョンチェック用のプロパティの値が1だったとします。 更新時にカラムの値が1のままならOKで、2に更新されます。 カラムの値が1でない場合は、他で更新されているということなので、 javax.persistence.OptimisticLockException が発生します。

注意点

@Versionアノテーションは数値型のフィールドにのみ指定することができます。JPA仕様ではTimestamp型のフィールドもバージョンチェックに使用できることになっていますが、S2JDBCではサポートしていません。更新時刻の保持と排他制御は目的が違うので別のフィールドにしてください。

java.lang.Enum のサブクラスは,デフォルトでは列挙定数の序数 ( Enum#ordinal() の戻り値) で扱われます. 列挙の扱いを変更するには、 @Enumerated を指定します。 @Enumerated で指定可能な値は次のとおりです。

EnumType.ORDINAL
列挙定数の序数 ( Enum#ordinal() の戻り値) で扱うことを指定します (デフォルト)。
EnumType.STRING
列挙定数の名前 ( Enum#name() の戻り値) で扱うことを指定します。
注意点

Seasar2.4.26までは、 @Enumerated はサポートされておらず、列挙は名前で扱われていました。 Seasra2.4.27以降で2.4.26以前と同じように @Enumerated の指定されていない列挙を名前で扱うには、 s2jdbc.dicon に次のように記述をしてください。

・・・ @org.seasar.extension.jdbc.types.ValueTypes@setEnumDefaultValueType( @org.seasar.extension.jdbc.types.EnumType@class) ]]>

java.util.Date および java.util.Calendar 型のプロパティには時制を指定します。 時制を指定するには、 @Temporal を使います。 @Temporal で指定可能な値は次のとおりです。

TemporalType.DATE
SQL標準の DATE 型 (日付のみ) として扱うことを指定します。
TemporalType.TIME
SQL標準の TIME 型 (時刻のみ) として扱うことを指定します。
TemporalType.TIMESTAMP
SQL標準の TIMESTAMP 型 (日付と時刻) として扱うことを指定します。
注意点

Seasar2.4.44 以降と Oracle の組み合わせの場合、デフォルトでは @Temporal(TemporalType.TIMESTAMP) で注釈された java.util.Date 型および java.util.Calendar 型のプロパティは、Oracle固有の DATE 型として扱われます。
Seasar2.4.43 以前と同様に @Temporal(TemporalType.TIMESTAMP) で注釈された java.util.Date 型および java.util.Calendar 型のプロパティをOracleの TIMESTAMP 型として扱いたい場合は、 s2jdbc.dicon で OracleDialect の useOracleDate プロパティに false を設定してください。

false ... ]]>

byte[] ・ Serializable ・ String 型のプロパティはラージオブジェクトにすることができます。 ラージオブジェクトであることを指定するには、 @Lob を使います。

@Lob が指定されたプロパティが byte[] ・ Serializable 型ならBLOB、 String 型ならCLOBとなります。

ラージオブジェクトのようにサイズが大きくなるプロパティや、 通常は必要としないプロパティは SQL自動生成 による 検索 でフェッチの対象から除外することができます ( 指定したプロパティをフェッチ対象にする ことも可能です)。

フェッチ対象外であることを指定するには、 @Basic の fetch 要素を使います。

注意点

S2JDBCは遅延ロードを サポートしません 。

FetchType.LAZY が指定されたプロパティは遅延ロードの対象になるのではなく、単に 取得されない だけで、プロパティの値は初期値のままとなります。

永続化対象外であることを指定するには、 @Transient を使います。 transient 修飾子も指定することもできますが、セッションリプリケーションなどの直列化の対象から外れてしまうので、 @Transient の方をお勧めします。

多対一関連であることを指定するには、 @ManyToOne を使います。複数の Employee に1つの Departement が関連付けられる場合、 Employee からみて Department は多対一関連になります。 関連には、所有者、被所有者という概念があり、外部キーを持っているほうが所有者になります。

上記のケースは、 Employee のテーブルに、 department_id (プロパティ名は departmentId )という外部キーがあるので、 Employee は関連の所有者になります。

@ManyToOne を定義するエンティティは、必ず関連の所有者になるので、外部キーに対応するプロパティが必要です。

一対多関連であることを指定するには、 @OneToMany を使います。1つの Department に複数の Employee が関連付けられる場合、 Department からみて Employee は一対多関連になります。 関連には、所有者、被所有者という概念があり、外部キーを持っているほうが所有者になります。

上記のケースは、 Employee のテーブルに、 department_id (プロパティ名は departmentId )という外部キーがあり、 Department の方は、外部キーを持っていないので、 Department は関連の被所有者になります。

関連の被所有者の場合、必ず mappedBy 要素で逆側の関連のプロパティ名を指定します。 Department からみて一対多で Employee が関連付けられていて、その Employee からみると Department が department プロパティとして、多対一で関連付けられています。 お互いが相互の関連であることを示すために mappedBy で department を指定します。

一対多の関連の型は、 List<エンティティ型> にします。 どのエンティティのリストなのかを示すためにGenericsの指定を忘れないようにしてください。

employeeList; } ]]>

一対一関連であることを指定するには、 @OneToOne を使います。1つの Employee に1つの Address が関連付けられる場合、 Employee からみて Address は一対一関連になります。同じように、1つの Address に1つの Employee が関連付けられているので、 Address からみて Employee も一対一関連になります。 関連には、所有者、被所有者という概念があり、外部キーを持っているほうが所有者になります。

上記のケースは、 Employee のテーブルに、 address_id (プロパティ名は addressId )という外部キーがあるので、 Employee は関連の所有者になります。 Address の方は、外部キーを持っていないので、 Address は関連の被所有者になります。

関連の被所有者の場合、必ず mappedBy 要素で逆側の関連のプロパティ名を指定します。 Address から見ると一対一で Employee が関連付けられていて、その Employee からみると Address が address プロパティとして、一対一で関連付けられています。 お互いが相互の関連であることを示すために mappedBy で addressを指定します。

外部キーを持っている方を関連の所有者といいますが、関連の所有者側では、 @JoinColumn を使って、結合用のカラムを指定することができます。

name 要素で、外部キーを指定します。 name 要素を省略した場合、「 関連のプロパティ名_関連テーブルの主キー 」が 自動的に設定されます。 主キーは、プロパティ名ではなく、カラム名なので注意してください。

上記の例では、 @JoinColumn が省略されているので、 name 要素は、「 関連のプロパティ名(department)_関連テーブルの主キー(ID) 」、つまり DEPARTMENT_ID になります。

department が DEPARTMENT に変換されているのは、プロパティ名をカラム名に変換するときに、キャメル記法は、 '_' 区切りになり、 '_' 以外は大文字に変換されるというルールがあるからです。

このルールは、 convention.dicon で指定されている org.seasar.framework.convention.impl.PersistenceNamingConventionImpl の fromPropertyNameToColumnName() の実装を変えることで、カスタマイズすることができます。

referencedColumnName 要素で、関連テーブルの主キーを指定します。 referencedColumnName 要素を省略した場合、 「関連テーブルの主キー」が自動的に設定されます。 主キーは、プロパティ名ではなく、カラム名なので注意してください。

上記の例では、 @JoinColumn が省略されているので、 referencedColumnName 要素は、「 関連テーブルの主キー(ID) 」、つまり IDになります。