Entity
- Entityとは?
- Entityの使い方
- 区分値 (Classification)
- 共通カラム (CommonColumn)
- 基本メソッドのオーバーライド
- Entityの構造
- ValueTypeの調整
Entityとは?
DBのデータをプログラム上に反映させるためのオブジェクトです。えんてぃてぃ と呼びます。
大きく分けて テーブル対応のEntity と SQL対応のEntity があります。前者を DomainEntity(どめいんえんてぃてぃ) と呼び、後者を CustomizeEntity(かすたまいずえんてぃてぃ) と呼びます。単に Entity と言う場合は、両方を抽象的に取り扱う場合、もしくは、前者の方を示す場合が主となります。
- テーブル対応のEntity
- DomainEntity
- SQL対応のEntity
- CustomizeEntity
自動生成される
DBFluteでは、全てのEntityは自動生成されます。DomainEntity はテーブル情報からGenerateタスクにて、CustomizeEntityはSQL情報からSql2Entityタスクにて。
ジェネレーションギャップで自動生成されるため、EntityのExクラスにはアプリケーション独自のプロパティや処理を定義することができます。 特に、ConditionBeanの (Specify)DerivedReferrer ではこの構造を活かし、子テーブルの導出カラムのプロパティをEntityのExクラスに定義することで機能を実現します。
Entityのクラス名
テーブル名のキャメルケース です。例えば、MEMBER_STATUS なら MemberStatus。もし、ProjectPrefix を指定している場合は、指定した prefix がクラス名の先頭に付与されます。
プロパティ設定の記録
DBFluteのEntityの特徴として、プロパティ設定(セッターの呼び出し)を内部で記録していることです。 これにより、どのプロパティ(カラム)がアプリケーションにて更新されたかが判明するため、更新時などで 設定されたカラムのみを更新対象とする ことができます。
Entityの使い方
インスタンス生成
検索時は、DBFlute内部でインスタンスが生成されます。
e.g. 検索時にBehaviorからEntityを受け取る {Member} @Java
MemberCB cb = new MemberCB();
cb.query().setMemberId_Equal(3); // 会員IDが 3 の会員を検索
Member member = memberBhv.selectEntity(cb);
登録、更新、削除時は、アプリケーションでインスタンスを生成します。
e.g. 更新時にEntityを生成してBehaviorに渡す {Member} @Java
Member member = new Member();
member.setMemberId(3);
member.setMemberName("foo"); // 会員名称を "foo" に更新
memberBhv.update(member);
インスタンスを生成するときは、必ず Exクラス の方の型で生成します。"Bs" の付いたジェネレーションギャップのための(スーパー)クラスをインスタンス生成してはいけません。
カラム対応プロパティの取得、設定
get[プロパティ名](...) メソッドにて取得、set[プロパティ名]() メソッドにて設定します。
e.g. カラム対応プロパティの設定、取得 {Member} @Java
Member member = new Member();
member.setMemberName("foo"); // 会員名称を "foo" に設定
String memberName = member.getMemberName(); // 会員名称を取得 ("foo")
- 検索は get、更新は set
- アプリケーションは、検索時は主に get を利用し(検索結果の取得)、登録、更新、削除時は主に set を利用する(更新内容の設定)、という形になります(例外的に、登録や更新後に自動設定された値を取得するのに get を利用することもあります)。
- キャメルケースコード補完の活用
- キャメルケースコード補完で、スムーズにメソッドを呼び出せます。例えば、getMemberName() メソッドであれば、getMN と打ち込めばかなり候補から選びやすくなるでしょう。
リレーション対応プロパティの取得、設定
get[プロパティ名](...) メソッドにて取得、set[プロパティ名]() メソッドにて設定します。
e.g. many-to-one プロパティの設定、取得 {MEMBER_STATUS} @Java
Member member = new Member();
member.setMemberStatus(new MemberStatus()); // 会員ステータスを設定
MemberStatus memberName = member.getMemberStatus(); // 会員ステータスを取得
e.g. one-to-many プロパティの設定、取得 {PURCHASE} @Java
Member member = new Member();
member.setPurchaseList(new ArrayList<Purchase>()); // 購入リストを設定
List<Purchase> purchaseList = member.getPurchaseList(); // 購入リストを取得
- set はあまり利用しない
- リレーション対応プロパティに対してアプリケーションが設定処理(set)を行う必要性はほとんどありません。 例えば、検索結果データのEntityへの設定処理は、DBFlute内部にて実行されます。 また、Entityに格納されたリレーションデータを利用して更新処理を行う機能は存在しません。 (Entity をアプリケーション独自に "ただの入れ物" として扱うような場合のみ、利用する可能性があるかもしれません)
- キャメルケースコード補完の活用
- キャメルケースコード補完で、スムーズにメソッドを呼び出せます。例えば、getMemberStatus() メソッドであれば、getMS と打ち込めばかなり候補から選びやすくなるでしょう。
メタデータの取得
基本的にアプリケーションで意識する必要はありません。
アプリケーションの中の仕組み(共通部分の実装など)で、どうしても必要になったときは、Entity のインスタンスからテーブル名や DBMeta を取得することができます。
e.g. メタデータの取得 {MemberStatus} @Java
MemberStatus status = new MemberStatus();
String tableDbname = status.getTableDbName(); // DB上の名前 "MEMBER_STATUS"
String propertyName = status.getPropertyName(); // プロパティ名 "memberStatus"
DBMeta dbmeta = status.getDBMeta(); // 会員ステータスのDBMeta
区分値 (Classification)
区分値が関連付いていると、区分値をタイプセーフに扱える区分値メソッドが利用できます。
e.g. 区分値の設定や判定 @Java
Member member = new Member();
member.setMemberStatusCode_Formalized(); // 設定メソッド (正式会員にする)
...
if (member.isMemberStatusCodeFormalized()) { // 判定メソッド (正式会員かどうか)
...
}
区分値の設定
set[プロパティ名]_[区分値要素の名前]() の形式のメソッドを利用します。
e.g. 区分値の設定(メソッド解決)。会員ステータスコードに正式会員を設定 @Java
Member member = new Member();
member.setMemberStatusCode_Formalized();
// member.setMemberStatusCode("FML"); と同義
- 通常のプロパティの設定と同じ set 始まり
- 通常のプロパティの設定と同じ set 始まりのメソッドなので、他のカラムと同様、とりあえず set と打って、対象のカラムの set メソッドを補完すると、区分値メソッドが補完候補に並びますので、後はそこから選ぶだけです。 その時、ネイティヴ型の設定メソッドしか存在しない場合は、区分値が関連付けられていません(設定漏れ)ので、(ディベロッパーは)アーキテクトに相談しましょう。
- キャメルケースコード補完の活用
- キャメルケースコード補完で、スムーズにメソッドを呼び出せます。例えば、setMemberStatusCode_Formalized() メソッドであれば、setMSCF と打ち込めばほぼピンポイントで絞り込めるでしょう。
- CDef を直接渡すメソッド
-
メソッド名解決のメソッドに対し、ENUMである CDef を直接渡すメソッドもあります。但し、基本的にはあまり利用する必要はありません。
主に、(後述の)ネイティヴ型の設定メソッドがオプションで利用できない状態で、画面のFormから飛んで来た値を設定するような場合に利用します。
e.g. 区分値の設定(CDef指定)。会員ステータスコードにFormのステータスを設定 @Java
Member member = new Member(); CDef.MemberStatus cdefStatus = CDef.MemberStatus.codeOf(form.status); member.setMemberStatusCodeAsMemberStatus(cdefStatus);
- ネイティヴ型の設定メソッドは残ったまま
-
区分値が関連付いたカラムのネイティヴ型での設定メソッドは残っています。
ですが、よほどのことがない限り、区分値コードをハードコードした利用は絶対にやってはいけません。
e.g. (ディベロッパーが)絶対にやってはいけないやり方 @Java
member.setMemberStatusCode("FML"); // 絶対にだめ
- ネイティヴ型のメソッドが補完候補となる場合、一緒に区分値メソッドも候補として表示されるため、 区分値メソッドの存在に気付かずにネイティヴ型を使ってしまうケースはあまりないでしょうが、"念には念を" ということで、DBFluteプロパティのオプションで、このメソッドを削除して利用できないようにすることができます。
区分値の判定
is[プロパティ名][区分値要素の名前]() の形式のメソッドを利用します。
e.g. 区分値の判定。会員ステータスコードが正式会員であること @Java
Member member = memberBhv.selectEntity(cb);
if (member.isMemberStatusCodeFormalized()) {
...
}
// if ("FML".equalsIgnoreCase(member.getMemberStatusCode())) { と同義
- Entityで is で始まるメソッドはこれだけ
- entity.is とまで打ち込めば、is[区分値] メソッドだけが補完候補となります。 逆に何も候補が挙がらなければ、区分値が関連付けられていません(設定漏れ)ので、(ディベロッパーは)アーキテクトに相談しましょう。
- キャメルケースコード補完の活用
- キャメルケースコード補完で、スムーズにメソッドを呼び出せます。例えば、isMemberStatusCodeFormalized() メソッドであれば、isMSCF と打ち込めばほぼピンポイントで絞り込めるでしょう。
区分値要素の名前、別名の取得
get[プロパティ名][Name or Alias]() の形式のメソッドを利用します。
e.g. 区分値要素の名前、別名。(正式会員) @Java
Member member = memberBhv.selectEntity(cb);
String name = member.getMemberStatusCodeName(); // "Formalized"
String alias = member.getMemberStatusCodeAlias(); // "正式会員"
別名(alias)は、設定として必須ではないので、定義がない場合はメソッド自体が存在しません。
これらメソッドで取得される値は、自動生成時に解決されたものです。 特にテーブル区分値のときに関する話ですが、自動生成時にデータベース上から検索された値であり、メソッドを呼び出し瞬間のデータベース上の値ではありません。 これらの値を利用するかどうか、それとも検索で関連テーブルの値を取得するか、プロジェクトのポリシーを確認してからご利用下さい。
共通カラム (CommonColumn)
共通カラムの設定が有効で、共通カラムを持っているテーブルのEntityは EntityDefinedCommonColumn インターフェースを実装 します。
ほとんどの場合において、アプリケーションでこのインターフェースを意識する必要はない のですが、例えば、移行プログラムの実装で、ここの処理だけ共通カラムの自動設定の機能を無効にしたいというような要件 がある場合には、disableCommonColumnAutoSetup() メソッドを利用します。旧システムの登録日時や更新日時を保ったまま新システムに移行するような場合です。
e.g. 共通カラムの自動設定を(この処理だけ)無効にする @Java
Member member = ...; // 旧システムの情報を格納 (共通カラムの情報も含めて)
member.disableCommonColumnAutoSetup();
memberBhv.insert(member);
ただし、無効化に関しては、varyingInsert() や varyingUpdate() などのオプション付きメソッドでも実現可能です(@since 0.9.7.8)。 (通常は、varyingInsert() や varyingUpdate() のオプションによる無効化の方が推奨されます)
基本メソッドのオーバーライド
equals()メソッド
PK の値で比較します。
hashCode()メソッド
PK の値で計算します。
toString()メソッド
クラス名 + Entity に定義されている全てのカラムのデータ + ハッシュコードを表示します。 参照しているリレーションの情報は表示されません。
clone()メソッド
Object型 の clone() を利用した clone() メソッドが用意されています(@since 0.9.9.1B)。
Entityの構造
全ての(自動生成される)Entityは、Entity インターフェースを実装しています。共通クラス対応のEntityも同様で、EntityDefinedCommonColumn インターフェース自体が Entity インターフェースの拡張インターフェースです。また、必ず Serializable インターフェースを実装しています。
e.g. EntityのBsクラスの宣言 {BeMember} @Java
public class BsMember implements EntityDefinedCommonColumn, Serializable {
e.g. EntityDefinedCommonColumnの宣言 @Java
public interface EntityDefinedCommonColumn extends Entity {
Entity要素の一覧
- カラム対応のプロパティ
- get...、set...
- 関連テーブル対応のプロパティ
- get...、set...
- メタデータ
- getTableDbName()、getDBMeta()、... (internal)
- 共通カラム
- enable...、disable...、can...
- 区分値
- classify...、is...、get...
- 更新記録
- ...ModifiedPropertyNames... (very internal)
- その他
- hasPrimaryKeyValue()、toStringWithRelation()など
PKの抽象化
PK の値を持っているかどうか、hasPrimaryKeyValue() で判定することができます。PKの構成カラムの中で一つでも値が存在しないものがあれば false です。
リレーションも表示する toString()
自身のデータだけでなく、参照しているリレーションのデータも一緒に表示するメソッド toStringWithRelation() があります。デバッグのために、中身を大げさに知りたい場合に手軽に利用できるメソッドです。
ValueTypeの調整
デフォルトの ValueType ではなく、カラムごとに独自の ValueType を指定することができます。これを利用することで、パラメータのJDBC周りの処理、"更新時のバインド処理" や "検索時の値の取得" などの調整ができます。(ただし、ConditionBean のバインド処理には影響しません。CB ではプロパティの型で ValueType が固定で決定します)
e.g. Entity のExクラスで独自の ValueType を定義 @Java
public class Member extends BsMember {
public static final String memberName_VALUE_TYPE = "fooType";
...
}
"[property-name]_VALUE_TYPE" という形式の定数アノテーションで、値は String 型で、"プラグインValueType" のキーの名前を指定します。"property-name" は JavaBeansRule ですので、先頭文字の大文字小文字にはご注意下さい。
基本的にBsクラスには定義されていませんが、特殊な方の場合にDBFluteが自動で設定することがあります。 同じ名前の定数をExクラスでも定義(上書き)した場合はExクラスでの定義が優先されます。
ValueType を独自に作成する必要はありますが、このように拡張することでサポートされない型も扱えるようになるかもしれません。