エンティティの定義の仕方を説明します。ここでいっているエンティティとは、 データベースに永続化されるものだと考えてください。
エンティティ用のアノテーションは、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
に次のように記述をしてください。
java.util.Date
および
java.util.Calendar
型のプロパティには時制を指定します。 時制を指定するには、
@Temporal
を使います。
@Temporal
で指定可能な値は次のとおりです。
TemporalType.DATE
DATE
型 (日付のみ) として扱うことを指定します。
TemporalType.TIME
TIME
型 (時刻のみ) として扱うことを指定します。
TemporalType.TIMESTAMP
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
を設定してください。
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の指定を忘れないようにしてください。
一対一関連であることを指定するには、
@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
になります。