概要
エンティティの定義の仕方を説明します。ここでいっているエンティティとは、 データベースに永続化されるものだと考えてください。
エンティティ用のアノテーションは、JPAのものをそのまま利用していますが、 すべてのアノテーションや要素をサポートしているわけではありません。 ここに取り上げられているもののみサポートされているとお考えください。
エンティティ定義
エンティティにするためには、
@Entity
を必ず指定する必要があります。
@Entity public class Employee { ... }
name
要素でエンティティ名を指定することができます。
次の例では、
Emp
というエンティティ名を指定しています。
@Entity(name = "Emp") public class Employee { ... }
name
要素を指定しなかった場合、エンティティのクラス名からパッケージ名を除いた部分が、
デフォルトのエンティティ名になります。例えば、クラス名が
examples.entity.Employee
の場合、デフォルトのエンティティ名は、
Employee
になります。
テーブル定義
テーブル情報を指定するには、
@Table
を使います。
name
要素でテーブル名を指定することができます。
指定しなかった場合、テーブル名はエンティティ名と同じになります。エンティティ名が、
AaaBbb
のようなキャメル記法の場合、テーブル名は、
AAA_BBB
のように
'_'
区切りだとみなされます。
このルールは、
convention.dicon
で指定されている
org.seasar.framework.convention.impl.PersistenceNamingConventionImpl
の
fromEntityNameToTableName()
の実装を変えることで、カスタマイズすることができます。
次の例では、
EMP
というテーブル名を指定しています。
@Entity @Table(name = "EMP") public class Employee { ... }
schema
要素でスキーマを指定することができます。
指定した場合、自動生成されるSQLのテーブル名がスキーマ.テーブル名になります。
catalog
要素でカタログを指定することができます。
指定した場合、自動生成されるSQLのテーブル名がカタログ.テーブル名になります。
catalog
要素と
schema
要素の両方を指定した場合、自動生成されるSQLのテーブル名はカタログ.スキーマ.テーブル名になります。
継承
エンティティは
@MappedSuperclass
が指定されたクラスを継承できます。
@MappedSuperclass public abstract class AbstractEmployee { ... }
@Entity public class Employee extends AbstractEmployee { ... }
@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
というカラム名を指定しています。
@Column(name = "AB1234") public String shortName;
insertable
要素で挿入可能かどうかを指定することができます。デフォルトは
true
です。
false
の場合、挿入用のSQLにこのカラムは含まれません。
カラムにデフォルト値を適用したい場合は、
false
にすると良いでしょう。
updatable
要素で更新可能かどうかを指定することができます。デフォルトは
true
です。
false
の場合、更新用のSQLにこのカラムは含まれません。
カラムにデフォルト値を適用したい場合は、
false
にすると良いでしょう。
識別子定義
識別子(主キー)であることを指定するには、
@Id
を使います。
@Id public Integer id;
複合主キーの場合は、
@Id
を複数つけます。
@Id public Integer id; @Id public Integer id2;
識別子は、アプリケーション側で生成することもできますが、 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 @GeneratedValue(strategy = GenerationType.TABLE) public Integer id;
上記のように指定した場合、あらかじめ、次のようなテーブルとデータを用意しておく必要があります。
create table ID_GENERATOR ( PK varchar(80) not null primary key, VALUE integer);
insert into ID_GENERATOR (PK, VALUE) values ('EMPLOYEE_ID', 1);
ID_GENERATOR
テーブルのPKカラムには、
<テーブル名>_<識別子のカラム名>
を設定します。
テーブル名やカラム名をカスタマイズするには、次のように
@TableGenerator
アノテーションで指定します。
@Id @GeneratedValue(strategy = GenerationType.TABLE, generator = "EMPLOYEE_GEN") @TableGenerator( name = "EMPLOYEE_GEN", table = "ID_GEN", pkColumnName = "GEN_NAME", valueColumnName = "GEN_VALUE") public Integer id;
上記のような
TableGenerator
を定義した場合、あらかじめ、次のようなテーブルとデータを用意しておく必要があります。
create table ID_GEN ( GEN_NAME varchar(80) not null primary key, GEN_VALUE integer);
insert into ID_GEN (GEN_NAME, GEN_VALUE) values ('EMPLOYEE_GEN', 1);
GenerationType.SEQUENCE
GenerationType.SEQUENCE
は次のようにして使います。
@Id @GeneratedValue(strategy = GenerationType.SEQUENCE) public Integer id;
上記のように指定した場合、あらかじめ、次のようなシーケンスを用意しておく必要があります。
create sequence EMPLOYEE_ID incremet by 50;
シーケンス名は、
<テーブル名>_<識別子のカラム名>
となります。
シーケンス名をカスタマイズするには、次のように
@SequenceGenerator
アノテーションで指定します。
@Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "EMPLOYEE_GEN") @SequenceGenerator( name = "EMPLOYEE_GEN", sequenceName = "EMPLOYEE_SEQ") public Integer id;
上記のような
SequenceGenerator
を定義した場合、
あらかじめ、次のようなシーケンスを用意しておく必要があります。
create sequence EMPLOYEE_SEQ incremet by 50;
GenerationType.IDENTITY
GenerationType.IDENTITY
は次のようにして使います。
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) public Integer id;
GenerationType.IDENTITY
を使う場合、識別子はデータベース固有の方法を使って自動生成されるようにしてください。
create table Employee { ID integer not null primary key generated always as identity, ...);
バージョン定義
バージョンチェック用であることを指定するには、
@Version
を使います。更新時に、エンティティの値とカラムの値が同一かどうかをチェックし、
同一ならカラムの値がインクリメントされて更新されます。同一でない場合、
javax.persistence.OptimisticLockException
が発生します。
例えば、エンティティのバージョンチェック用のプロパティの値が1だったとします。
更新時にカラムの値が1のままならOKで、2に更新されます。
カラムの値が1でない場合は、他で更新されているということなので、
javax.persistence.OptimisticLockException
が発生します。
@Version public Long version = 0L;
@Versionアノテーションは数値型のフィールドにのみ指定することができます。JPA仕様ではTimestamp型のフィールドもバージョンチェックに使用できることになっていますが、S2JDBCではサポートしていません。更新時刻の保持と排他制御は目的が違うので別のフィールドにしてください。
列挙定義
java.lang.Enum
のサブクラスは,デフォルトでは列挙定数の序数 (
Enum#ordinal()
の戻り値) で扱われます.
列挙の扱いを変更するには、
@Enumerated
を指定します。
@Enumerated
で指定可能な値は次のとおりです。
EnumType.ORDINAL
-
列挙定数の序数 (
Enum#ordinal()
の戻り値) で扱うことを指定します (デフォルト)。 EnumType.STRING
-
列挙定数の名前 (
Enum#name()
の戻り値) で扱うことを指定します。
public JobType jobType; //序数で扱われます @Enumerated public JobType jobType; //序数で扱われます @Enumerated(EnumType.ORDINAL) public JobType jobType; //序数で扱われます @Enumerated(EnumType.STRING) public JobType jobType; //名前で扱われます
Seasar2.4.26までは、
@Enumerated
はサポートされておらず、列挙は名前で扱われていました。
Seasra2.4.27以降で2.4.26以前と同じように
@Enumerated
の指定されていない列挙を名前で扱うには、
s2jdbc.dicon
に次のように記述をしてください。
<component name="jdbcManager" class="org.seasar.extension.jdbc.manager.JdbcManagerImpl"> ・・・ <!-- 以下を追加 --> <initMethod> @org.seasar.extension.jdbc.types.ValueTypes@setEnumDefaultValueType( @org.seasar.extension.jdbc.types.EnumType@class) </initMethod> </component>
時制定義
java.util.Date
および
java.util.Calendar
型のプロパティには時制を指定します。 時制を指定するには、
@Temporal
を使います。
@Temporal
で指定可能な値は次のとおりです。
TemporalType.DATE
-
SQL標準の
DATE
型 (日付のみ) として扱うことを指定します。 TemporalType.TIME
-
SQL標準の
TIME
型 (時刻のみ) として扱うことを指定します。 TemporalType.TIMESTAMP
-
SQL標準の
TIMESTAMP
型 (日付と時刻) として扱うことを指定します。
@Temporal(TemporalType.DATE) public Date date;
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
を設定してください。
<component name="jdbcManager" class="org.seasar.extension.jdbc.manager.JdbcManagerImpl"> <property name="dialect"> <component class="org.seasar.extension.jdbc.dialect.OracleDialect"> <property name="useOracleDate">false</property> </component> </property> ...
ラージオブジェクト定義
byte[]
・
Serializable
・
String
型のプロパティはラージオブジェクトにすることができます。 ラージオブジェクトであることを指定するには、
@Lob
を使います。
@Lob
が指定されたプロパティが
byte[]
・
Serializable
型ならBLOB、
String
型ならCLOBとなります。
@Lob public String largeName; @Lob public byte[] largeArray; @Lob public LargeDto largeDto;
フェッチ対象外定義
ラージオブジェクトのようにサイズが大きくなるプロパティや、 通常は必要としないプロパティは SQL自動生成 による 検索 でフェッチの対象から除外することができます ( 指定したプロパティをフェッチ対象にする ことも可能です)。
フェッチ対象外であることを指定するには、
@Basic
の
fetch
要素を使います。
@Basic(fetch = FetchType.LAZY) @Lob public LargeDto largeDto;
S2JDBCは遅延ロードを サポートしません 。
FetchType.LAZY
が指定されたプロパティは遅延ロードの対象になるのではなく、単に
取得されない
だけで、プロパティの値は初期値のままとなります。
関連定義
多対一関連定義
多対一関連であることを指定するには、
@ManyToOne
を使います。複数の
Employee
に1つの
Departement
が関連付けられる場合、
Employee
からみて
Department
は多対一関連になります。
関連には、所有者、被所有者という概念があり、外部キーを持っているほうが所有者になります。
上記のケースは、
Employee
のテーブルに、
department_id
(プロパティ名は
departmentId
)という外部キーがあるので、
Employee
は関連の所有者になります。
@ManyToOne
を定義するエンティティは、必ず関連の所有者になるので、外部キーに対応するプロパティが必要です。
public class Employee { ... public Integer departementId; @ManyToOne public Department department; }
一対多関連定義
一対多関連であることを指定するには、
@OneToMany
を使います。1つの
Department
に複数の
Employee
が関連付けられる場合、
Department
からみて
Employee
は一対多関連になります。
関連には、所有者、被所有者という概念があり、外部キーを持っているほうが所有者になります。
上記のケースは、
Employee
のテーブルに、
department_id
(プロパティ名は
departmentId
)という外部キーがあり、
Department
の方は、外部キーを持っていないので、
Department
は関連の被所有者になります。
関連の被所有者の場合、必ず
mappedBy
要素で逆側の関連のプロパティ名を指定します。
Department
からみて一対多で
Employee
が関連付けられていて、その
Employee
からみると
Department
が
department
プロパティとして、多対一で関連付けられています。
お互いが相互の関連であることを示すために
mappedBy
で
department
を指定します。
一対多の関連の型は、
List<エンティティ型>
にします。
どのエンティティのリストなのかを示すためにGenericsの指定を忘れないようにしてください。
public class Department { ... @OneToMany(mappedBy = "department") public List<Employee> 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
を指定します。
public class Employee { ... public Integer addressId; @OneToOne public Address address; }
public class Address { ... @OneToOne(mappedBy = "address") public Employee employee; }
結合カラム定義
外部キーを持っている方を関連の所有者といいますが、関連の所有者側では、
@JoinColumn
を使って、結合用のカラムを指定することができます。
name
要素で、外部キーを指定します。
name
要素を省略した場合、「
関連のプロパティ名_関連テーブルの主キー
」が 自動的に設定されます。
主キーは、プロパティ名ではなく、カラム名なので注意してください。
public class Employee { ... public Integer departementId; @ManyToOne public Department department; }
上記の例では、
@JoinColumn
が省略されているので、
name
要素は、「
関連のプロパティ名(department
)_関連テーブルの主キー(ID
)
」、つまり
DEPARTMENT_ID
になります。
department
が
DEPARTMENT
に変換されているのは、プロパティ名をカラム名に変換するときに、キャメル記法は、
'_'
区切りになり、
'_'
以外は大文字に変換されるというルールがあるからです。
このルールは、
convention.dicon
で指定されている
org.seasar.framework.convention.impl.PersistenceNamingConventionImpl
の
fromPropertyNameToColumnName()
の実装を変えることで、カスタマイズすることができます。
referencedColumnName
要素で、関連テーブルの主キーを指定します。
referencedColumnName
要素を省略した場合、
「関連テーブルの主キー」が自動的に設定されます。
主キーは、プロパティ名ではなく、カラム名なので注意してください。
public class Employee { ... public Integer departementId; @ManyToOne public Department department; }
上記の例では、
@JoinColumn
が省略されているので、
referencedColumnName
要素は、「
関連テーブルの主キー(ID
)
」、つまり
ID
になります。