エンティティ定義
エンティティクラスは @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.IDENTITY
GenerationType.SEQUENCE
GenerationType.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); }