エンティティ定義
エンティティクラスは @Entity
が注釈された非private
なクラスとして定義します。
クラスはトップレベルのクラスでなければいけません(他のクラスやインタフェースにネストされていてはいけません)。
エンティティクラスは abstract
であってはいけません。
@Entity public class Employee { ... }
エンティティがデータベースに対し挿入、更新、削除される直前に処理を実行したい場合、
listener
要素に org.seasar.doma.jdbc.entity.EntityListener
の実装クラスを指定できます。
@Entity(listener = EmployeeEntityListener.class) public class Employee { ... }
public class EmployeeEntityListener implements EntityListener<Employee> { @Override public void preDelete(Employee entity) { ... } @Override public void preInsert(Employee entity) { ... } @Override public void preUpdate(Employee entity) { ... } }
EntityListener
の実装クラスはpublicなデフォルトコンストラクタ(引数なしのコンストラクタ)を持たねばいけません。
エンティティに対応するテーブル名やプロパティに対応するカラム名を解決するための規約を変更したい場合、
namingConvention
要素に org.seasar.doma.jdbc.entity.NamingConvention
の実装クラスを指定できます。
@Entity(namingConvention = UpperCaseNamingConvention.class) public class Employee { ... }
public class UpperCaseNamingConvention.class implements NamingConvention { @Override public String fromEntityToTable(String entityName) { return entityName.toUpperCase(); } @Override public String fromPropertyToColumn(String propertyName) { return propertyName.toUpperCase(); } }
NamingConvention
の実装クラスはpublicなデフォルトコンストラクタ(引数なしのコンストラクタ)を持たねばいけません。
デフォルトでは、キャメルケースをアンダースコア区切りの大文字に変換するネーミング規約が使用されます。
たとえば、employeeName
というプロパティ名はEMPLOYEE_NAME
というカラム名に変換されます。
テーブル
エンティティに対応するテーブル情報を指定するには、 @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
要素を使用しない場合、
テーブル名は、org.seasar.doma.jdbc.NamingConvention
の実装クラスにより解決されます。
NamingConvention
の実装クラスは設定で決まります。
フィールド定義
永続的なフィールド
永続的なフィールドは、テーブルや結果セットのカラムに対応します。
フィールドの型は、基本型もしくは@Domain
が注釈されたクラスでなければいけません。
フィールドの可視性は非private
でなければいけません。
@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
要素を使用しない場合、
カラム名は、org.seasar.doma.jdbc.NamingConvention
の実装クラスにより解決されます。
NamingConvention
の実装クラスは設定で決まります。
識別子
識別子(主キー)であることを指定するには、@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インタフェースの@Updateが注釈されたメソッドを介して更新処理を実行する際、 UPDATE文のSET句に変更したフィールドのみを含めるようにすることが可能です。
@ChangedProperties
を注釈して示します。
フィールドの型はjava.util.Set<String>
でなければいけません。
フィールドの可視性は非private
でなければいけません。
@ChangedProperties Set<String> chagendProperties = new HashSet<String>();
変更されたフィールドの名前を@ChangedProperties
が注釈されたSetに追加するのはアプリケーション開発者の責任です。
フィールド名の追加は、永続的なフィールドに対応するsetterメソッドで行うのが適切です。
public void setEmployeeId(Integer employeeId) { chagendProperties.add("employeeId"); // フィールド名を@ChangedPropertiesが注釈されたSetに追加 this.employeeId = employeeId; }
メソッド定義
メソッドの定義に制限はありません。
フィールドの可視性をprotected
やパッケージプライベートにしてメソッド経由でアクセスすることも、
public
にして直接アクセスすることもどちらもサポートされています。
ただし、@ChangedProperties
を利用する場合は、メソッド経由のアクセスをすべきです。
エンティティの利用方法
インスタンス化して使用します。
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 public interface EmployeeDao { @Select EmpDeptDto selectByDepartmentId(Integer departmentId); }