エンティティ定義
エンティティクラスは @Entityが注釈されたクラスとして定義します。
クラスはトップレベルのクラスでなければいけません(他のクラスやインタフェースにネストされていてはいけません)。
エンティティクラスは 非privateなデフォルトコンストラクタ(引数なしのコンストラクタ)を持たなければいけません。
@Entity
public class Employee {
...
}
エンティティリスナー
エンティティがデータベースに対し挿入、更新、削除される直前/直後に処理を実行したい場合、
listener 要素に org.seasar.doma.jdbc.entity.EntityListener
の実装クラスを指定できます。
@Entity(listener = EmployeeEntityListener.class)
public class Employee {
...
}
listener 要素に何も指定しない場合、エンティティクラスが他のエンティティクラスを継承しているかどうかで採用する設定が変わります。
- 継承している場合、親エンティティクラスの設定を引き継ぎます
- 継承していない場合、何も行いません(
org.seasar.doma.jdbc.entity.NullEntityListenerが使用されます)
EntityListenerは、preDelete、preInsert、preUpdate、postDelete、postInsert、postUpdateの6つのメソッドをもったインタフェースです。
- preDelete
@Delete、または@BatchDeleteが注釈されたDaoメソッドでパラメータにエンティティが含まれる場合、削除処理の直前に呼び出されます。 ただし、使用するエンティティクラスにエンティティリスナーが指定されている必要があります。- preInsert
@Insert、または@BatchInsertが注釈されたDaoメソッドでパラメータにエンティティが含まれる場合、挿入処理の直前に呼び出されます。 ただし、使用するエンティティクラスにエンティティリスナーが指定されている必要があります。- preUpdate
@Update、または@BatchUpdateが注釈されたDaoメソッドでパラメータにエンティティが含まれる場合、更新処理の直前に呼び出されます。 ただし、使用するエンティティクラスにエンティティリスナーが指定されている必要があります。- postDelete
@Delete、または@BatchDeleteが注釈されたDaoメソッドでパラメータにエンティティが含まれる場合、削除処理の直後に呼び出されます。 ただし、使用するエンティティクラスにエンティティリスナーが指定されている必要があります。- postInsert
@Insert、または@BatchInsertが注釈されたDaoメソッドでパラメータにエンティティが含まれる場合、挿入処理の直後に呼び出されます。 ただし、使用するエンティティクラスにエンティティリスナーが指定されている必要があります。- postUpdate
@Update、または@BatchUpdateが注釈されたDaoメソッドでパラメータにエンティティが含まれる場合、更新処理の直後に呼び出されます。 ただし、使用するエンティティクラスにエンティティリスナーが指定されている必要があります。
EntityListenerは次のように実装できます。
public class EmployeeEntityListener implements EntityListener<Employee> {
@Override
public void preDelete(Employee entity, PreDeleteContext<Employee> context) {
...
}
@Override
public void preInsert(Employee entity, PreInsertContext<Employee> context) {
...
}
@Override
public void preUpdate(Employee entity, PreUpdateContext<Employee> context) {
...
}
@Override
public void postDelete(Employee entity, PostDeleteContext<Employee> context) {
...
}
@Override
public void postInsert(Employee entity, PostInsertContext<Employee> context) {
...
}
@Override
public void postUpdate(Employee entity, PostUpdateContext<Employee> context) {
...
}
}
EntityListenerの各メソッドの2番目のパラメータは挿入、更新、削除が行われた場合のコンテキスト情報です。
このコンテキスト情報には、エンティティのメタクラス、Daoのメソッド、Daoの設定が含まれます。
たとえば、Daoのメソッドに独自のアノテーションをつけておくと、そのアノテーションの有無を見て特定のプロパティを更新するといったことが可能です。
EntityListenerの実装クラスはpublicなデフォルトコンストラクタ(引数なしのコンストラクタ)を持たねばいけません。
ネーミング規約
エンティティに対応するテーブル名やプロパティに対応するカラム名を解決するためのネーミング規約を変更したい場合、
naming 要素に org.seasar.doma.jdbc.entity.NamingType
の列挙型を指定できます。
@Entity(naming = NamingType.SNAKE_UPPER_CASE)
public class EmployeeInfo {
...
}
naming 要素に何も指定しない場合、エンティティクラスが他のエンティティクラスを継承しているかどうかで採用する設定が変わります。
- 継承している場合、親エンティティクラスの設定を引き継ぎます
- 継承していない場合、何も行いません(
org.seasar.doma.jdbc.entity.NamingType.NONEが使用されます)
NamingType.SNAKE_UPPER_CASEは、エンティティ名やプロパティ名をスネークケース(アンダースコア区切り)の大文字に変換します。この例の場合、テーブル名はEMPLOYEE_INFOになります。
naming要素に何も指定しない場合、デフォルトでは、テーブル名にはエンティティクラスの単純名、カラム名にはプロパティ名が使用されます。
ネーミング規約は、@Tableや@Columのname要素が指定されない場合のみ使用されます。
@Tableや@Columのname要素が指定された場合は、name要素に指定した値が使用され、ネーミング規約は適用されません。
NamingTypeには次の列挙定数があります。
| 列挙定数 | 説明 |
|---|---|
| NONE | 何も行いません。 |
| SNAKE_UPPER_CASE | キャメルケースをスネークケース(アンダースコア区切り)の大文字に変換します。 |
| SNAKE_LOWER_CASE | キャメルケースをスネークケース(アンダースコア区切り)の小文字に変換します。 |
| UPPER_CASE | 大文字に変換します。 |
| LOWER_CASE | 小文字に変換します。 |
テーブル
エンティティに対応するテーブル情報を指定するには、 @Table を使用します。
name要素でテーブル名を指定できます。
@Entity
@Table(name = "EMP")
public class Employee {
...
}
catalog要素や schema要素 でカタログやスキーマを指定できます。
@Entity
@Table(catalog = "CATALOG", schema ="SCHEMA", name = "EMP")
public class Employee {
...
}
@Tableを使用しない、もしくは @Tableのname要素を使用しない場合、
テーブル名は、ネーミング規約により解決されます。
フィールド定義
永続的なフィールド
永続的なフィールドは、テーブルや結果セットのカラムに対応します。
フィールドの型は、基本型もしくはドメインクラスでなければいけません。
@Entity
public class Employee {
...
Integer employeeId;
}
カラム
プロパティに対応するカラム情報を指定するには、@Columnを使用します。
name要素でカラム名を指定できます。
@Column(name = "ENAME") String employeeName;
insertable要素や updatable要素 で挿入や更新の対象とするかどうかを指定できます。
@Column(insertable = false, updatable = false) String employeeName;
@Columnを使用しない、もしくは@Columnの name要素を使用しない場合、
カラム名は、ネーミング規約により解決されます。
識別子
識別子(主キー)であることを指定するには、@Idを使います。
@Id Integer id;
複合主キーの場合は @Id を複数指定します。
@Id Integer id; @Id Integer id2;
識別子を自動生成する場合は、@GeneratedValueを使用し、
生成方法をstrategy要素に指定します。
このアノテーションが注釈されるフィールドの型は数値のプリミティブ型、
もしくはNumberのサブタイプでなければいけません。
strategy 要素に指定できる方法は、次の3つです。
GenerationType.IDENTITYGenerationType.SEQUENCEGenerationType.TABLE
GenerationType.IDENTITY
データベースのIDENTITY自動生成機能を利用する方法です。RDBMSによってはサポートされていません。 フィールドに対応するカラムの定義でIDENTITY自動生成を有効にしておく必要があります。
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) Integer id;
GenerationType.SEQUENCE
データベースのシーケンスを利用する方法です。RDBMSによってはサポートされていません。
GenerationType.SEQUENCEを使用するには、
@SequenceGeneratorを併記します。
@SequenceGeneratorでは、シーケンスの名前、割り当てサイズ、初期値等を設定できます。
データベースにあらかじめシーケンスを定義しておく必要がありますが、その定義は@SequenceGeneratorの定義とあわせておく必要があります。
@Id @GeneratedValue(strategy = GenerationType.SEQUENCE) @SequenceGenerator(sequence = "EMPLOYEE_SEQ") Integer id;
GenerationType.TABLE
生成される識別子をテーブルで管理する方法です。すべてのRDBMSで利用できます。
GenerationType.TABLEを使用するには、
@TableGeneratorを併記します。
@TableGeneratorでは、テーブル名、割り当てサイズ、初期値等を設定できます。
データベースにあらかじめテーブルを定義しておく必要がありますが、その定義は@TableGeneratorの定義とあわせておく必要があります。
デフォルトでは、「ID_GENERATOR」という名前のテーブルに、文字列型の「PK」と数値型の「VALUE」という2つのカラムが定義されているものとして動作します(「PK」カラムが主キーです)。
「PK」カラムにはエンティティクラスごとの一意な名前、「VALUE」カラムには識別子の値が格納されます。
テーブルには、エンティティクラスごとのレコードをあらかじめ登録しておく必要があります。
@Id @GeneratedValue(strategy = GenerationType.TABLE) @TableGenerator(pkColumnValue = "EMPLOYEE_ID") Integer id;
@TableGeneratorのpkColumnValue要素には、
識別子を管理するテーブル(デフォルトでは、「ID_GENERATOR」という名前のテーブル)の主キーの値を指定します。
バージョン
楽観的排他制御用のバージョンは@Versionを注釈して示します。
フィールドの型は数値のプリミティブ型
もしくはNumberのサブタイプでなければいけません。
@Version Integer version;
非永続的なフィールド
非永続的なフィールドは、テーブルや結果セットのカラムに対応しません。
@Transientを注釈して示します。
フィールドの型や可視性に制限はありません。
@Transient BigDecimal tempSalary;
@Transient List<String> nameList;
取得時の状態を管理するフィールド
取得時の状態とは、エンティティがDaoから取得されときの全プロパティの値です。 取得時の状態を保持しておくことで、Daoインタフェースの@Updateが注釈されたメソッドを介して更新処理を実行する際、 UPDATE文のSET句に変更したフィールドのみを含めるようにすることが可能です。 取得時の状態を管理するフィールドは、テーブルや結果セットのカラムに対応しません。
@OriginalStatesを注釈して示します。
フィールドの型はフィールドが属するエンティティクラスと同じ型でなければいけません。
@OriginalStatesが注釈されたフィールドはアプリケーションで初期化したりアクセスしたりしてはいけません。
@OriginalStates Employee originalStates;
@OriginalStatesが注釈されたフィールドを持つエンティティの利用法は次のとおりです。
@Entity
public class Employee {
@Id
Integer id;
String name;
Integer age;
@OriginalStates
Employee originalStates;
...
}
EmployeeDao dao = new EmployeeDaoImpl(); Employee employee =dao.selectById(1); emoloyee.setAge(employee.getAge() + 1); dao.update(employee);
この例では、UPDATE文のSET句にAGEカラムだけが含まれます。
メソッド定義
メソッドの定義に制限はありません。
フィールドの可視性をprotectedやパッケージプライベートにしてpublicなメソッド経由でアクセスすることも、
メソッドを一切使用せずpublicフィールドに直接アクセスすることもどちらもサポートされています。
エンティティの利用方法
インスタンス化して使用します。
Employee employee = new Employee();
employee.setEmployeeId(1);
employee.setEmployeeName("SMITH");
employee.setSalary(new BigDecimal(1000));
エンティティはテーブルに1対1で対応させなければいけないわけではありません。
たとえば、EMPLOYEEテーブルとDEPARTMENTテーブルを結合した結果もエンティティにマッピングできます。
そのエンティティクラスをEmpDeptDtoとした場合のエンティティクラスの定義とDaoインタフェースの定義は次のとおりです。
@Entity
public class EmpDeptDto {
String employeeName;
String departmentName;
}
@Dao(config = AppConfig.class)
public interface EmployeeDao {
@Select
EmpDeptDto selectByDepartmentId(Integer departmentId);
}
