JavaのORMapperであるDoma2のエンティティはデフォルトでInteger型やString型などの基本型にマッピングされる。
ドメインクラスを定義することで、任意のクラスにマッピングさせることができる。
サンプルでは以下のDDLで生成されるテーブルを使用する。
create table sample ( id VARCHAR(128) not null , customer_status_cd CHAR(1) not null , name NVARCHAR(30) , phone_no VARCHAR(13) , constraint sample_PKC primary key (id) );
なお、基本型のみで定義されるエンティティは以下の通り。
import java.time.LocalDateTime; import org.seasar.doma.Column; import org.seasar.doma.Entity; import org.seasar.doma.Id; import org.seasar.doma.Table; import lombok.EqualsAndHashCode; import lombok.ToString; @Entity @Table(name = "sample") @ToString @EqualsAndHashCode public class Sample { @Id @Column(name = "id") String id; @Column(name = "customer_status_cd") String customerStatusCd; @Column(name = "name") String name; @Column(name = "phone_no") String phoneNo; // getter, setter 省略 }
①ドメインクラスの定義
サンプルのエンティティで、「phoneNo」を任意のクラスにマッピングさせるのを例に、実装方法を記載する。
1. エンティティでマッピングに使用するクラスに@Domain
アノテーションを付与する
アノテーションの属性値 valueType には 基本型 を指定する。
@Domain(valueType = String.class) public class PhoneNumber { }
2. アノテーションの属性factoryMethod
でインスタンスを生成するためのメソッド名を指定する
デフォルト値は new であり、privateでないコンストラクタでインスタンスを生成する。
そのため、コンストラクタでインスタンスを生成する場合は属性factoryMethodを省略することが出来る。
// このクラスの場合、publicなコンストラクタでインスタンスを生成可能なため、 // 属性「factoryMethod」は省略可能。 @Domain(valueType = String.class) public class PhoneNumber { private String number; public PhoneNumber(String number) { this.number = number; } }
コンストラクタではなく別のメソッドでインスタンスを生成したい場合、
privateでないstaticなファクトリーメソッドを定義し、属性 factoryMethod にそのメソッドの名前を指定する。
@Domain(valueType = String.class, factoryMethod = "getInstance") public class PhoneNumber { private String number; private PhoneNumber(String number) { this.number = number; } public static PhoneNumber getInstance(String number) { return new PhoneNumber(number); } }
インスタンスを生成するメソッド(もしくはコンストラクタ)を呼ぶ上で、
引数がnullであることを許容する場合は、属性 acceptNull にtrueを設定する(デフォルト:false)。
@Domain(valueType = String.class, factoryMethod = "getInstance", acceptNull = true) public class PhoneNumber { private String number; private PhoneNumber(String number) { this.number = number; } public static PhoneNumber getInstance(String number) { return new PhoneNumber(number); } }
3. アノテーションの属性accessorMethod
でラップする値を取得するためのメソッド名を指定する
デフォルト値はgetValue
である。メソッド名を変更したい場合は属性accessorMethod
にメソッド名を指定する。
ここで指定するメソッドもprivateでないものとする。
accessorMethod
に指定したメソッドで返却される値は、DBから取得される値となるものとなるようにメソッドを指定する。
@Domain(valueType = String.class, factoryMethod = "getInstance", accessorMethod = "getNumber") public class PhoneNumber { private String number; private PhoneNumber(String number) { this.number = number; } public static PhoneNumber getInstance(String number) { return new PhoneNumber(number); } public String getNumber() { return number; } }
ドメインクラスはクラスだけでなくenumでも定義することが出来る。
以下はenumの定義例である。
import org.seasar.doma.Domain; @Domain(valueType = String.class, factoryMethod = "of") public enum CustomerStatusCode { BLANK("1"), FILLED("2"); private final String value; CustomerStatusCode(String value) { this.value = value; } public static CustomerStatusCode of(String value) { for (CustomerStatusCode code: CustomerStatusCode.values()) { if (code.value.equals(value)) { return code; } } throw new IllegalArgumentException(value); } public String getValue() { return value; } }
②エンティティの型を変更する
エンティティのフィールドの型を、作成したドメインクラスの型に変更する。
import java.time.LocalDateTime; import org.seasar.doma.Column; import org.seasar.doma.Entity; import org.seasar.doma.Id; import org.seasar.doma.Table; import lombok.EqualsAndHashCode; import lombok.ToString; @Entity @Table(name = "sample") @ToString @EqualsAndHashCode public class Sample { @Id @Column(name = "id") String id; @Column(name = "customer_status_cd") CustomerStatusCode customerStatusCd; @Column(name = "name") String name; @Column(name = "phone_no") PhoneNumber phoneNo; // getter, setter 省略 }
③ドメインクラスを使用したエンティティでのクエリの書き方
サンプルで使用するDaoインターフェースは以下の通り。
エンティティは上記で作成したものを使用する。
@ConfigAutowireable @Dao public interface SampleDao { @Select List<Sample> selectBySample(Sample entity); }
ドメインクラスを使用したエンティティでのselect文の記述例を示す。
select /*%expand*/* from sample where customer_status_cd = /* entity.customerStatusCd */'3'
※2023/03/05追記
自動生成時にもマッピングさせる
doma-codegen-pluginを使用して、GradleタスクでDaoやEntityを自動生成する方法は以下の記事を参照。
Entityの自動生成時にも任意のカラムを任意のクラスにマッピングさせたい場合は、以下の設定を追加する。
entityPropertyClassNamesFileを設定する
1. build.gradleのentityにentityPropertyClassNamesFileを設定する
entity { entityPropertyClassNamesFile = file("$projectDir/codegen-enum-mapping.properties") }
2. codegen-enum-mapping.propertiesを作成し、Entityのマッピングの定義を記述する。
codegen-enum-mapping.propertiesのサンプル
jp.co.sample.persistence.entity.Sample@customerStatusCd=jp.co.sample.constant.CustomerStatusCode