検索

検索を行うには、 @SelectをDaoのメソッドに注釈します。

selectByDepartmentName(String departmentName); ... }]]>

検索では、SQLファイルが必須です。 検索系のSQLを自動生成する機能はありません。

検索結果を受ける型には、基本型、ドメインクラス、エンティティクラス、]]>、また、それらを要素とするjava.util.Listを使用できますが、 エンティティクラスを利用する場合、エンティティクラスは検索結果に応じて作成する必要があります。

たとえば、EMPLOYEEテーブルに対応するEmployeeエンティティクラスが定義されている場合、 EMPLOYEEテーブルのカラムを含む結果セットはEmployeeエンティティクラスで受けられますが、 EMPLOYEEテーブルとDEPARTMENTテーブルを結合して得られる結果セットに対しては、Employeeエンティティクラスとは別のクラス(たとえばEmployeeDepartmentクラス)が必要です。 通常は、テーブルごとにエンティティクラスを作成し、結合して得られる結果セットに対しては、テーブルに対応するエンティティクラスを継承したクラスを作成するのがよいでしょう。 もちろん、継承せずに作成することも可能です。

問い合わせ条件にはメソッドのパラメータを使用します。 パラメータの型には、基本型ドメインクラス、任意の型、 および基本型ドメインクラスを要素とするjava.lang.Iterableのサブタイプが使用できます。 パラメータの数に制限はありません。 パラメータの型が基本型もしくはドメインクラスの場合、引数をnullにできます。 それ以外の型の場合、引数はnullであってはいけません。

selectByNameAndSalary(String name, BigDecimal salary);]]>

SQLファイルではSQLコメントを使いメソッドのパラメータをSQLにマッピングさせます。 SQLコメントではメソッドのパラメータ名を参照します。

/* salary */100]]>

メソッドのパラメータに任意の型を使用する場合は、ドット(.)でフィールドにアクセスしたりメソッドを呼び出すなどしてSQLにマッピングさせます。

selectByExample(Employee employee);]]> /* employee.getSalary() */100]]>

任意の型であっても複数のパラメータを指定できます。

selectByEmployeeAndDepartment(Employee employee, Department department);]]>

基本型ドメインクラスを要素とするjava.lang.Iterableのサブタイプは、 IN句を利用した検索を行う場合に使用します。java.lang.Iterableのサブタイプは、通常java.util.Listが適切でしょう。

selectByNames(List names);]]>

複数件を検索するには、メソッドの戻り値の型をjava.util.Listにします。 Listの要素の型には、基本型ドメインクラスエンティティクラス]]>が使用できます。

selectByNameAndSalary(String name, BigDecimal salary);]]>

結果が0件のときは、空のListが返されます。nullは返されません。 ただし、@SelectのensureResult要素にtrueを指定した場合、 結果が0件ならばorg.seasar.doma.jdbc.NoResultExceptionがスローされます。

1件を検索するには、メソッドの戻り値の型を基本型ドメインクラスエンティティクラス]]>のいずれかにします。

結果が0件のときは、nullが返されます。 ただし、@SelectのensureResult要素にtrueを指定した場合、 結果が0件ならばorg.seasar.doma.jdbc.NoResultExceptionがスローされます。

結果が2件以上存在するときは、org.seasar.doma.jdbc.NonUniqueResultExceptionがスローされます。

全件を一度にListで受け取るのではなく1件ずつ処理を行いたい場合は、 イテレーションによる検索ができます。 イテレーションによる検索を行うには、@Selectiterate要素をtrueに設定し、 メソッドのパラメータに]]>もしくは、 ]]>のサブタイプを定義します。

callback);]]>

iterateメソッドに検索対象がインスタンス化され1件ずつ渡されます。

() { @Override public Void iterate(Employee target, IterationContext context) { ... return null; } });]]>

]]>の最初の型パラメータは、 Daoのメソッドの戻り値にあわせなければいけません。2番目の型パラメータは、基本型ドメインクラスエンティティクラス]]>のいずれかでなければいけません。

@SelectのensureResult要素にtrueを指定した場合、 結果が0件ならばorg.seasar.doma.jdbc.NoResultExceptionがスローされます。

イテレーションが完了した後に任意の処理を行うには、]]>の代わりに ]]>のサブタイプを定義します。 イテレーション完了後にpostIterateが呼び出されます。

() { @Override public Void iterate(Employee target, IterationContext context) { ... return null; } @Override public Void postIterate(Void result, IterationContext context) { ... return null; } });]]>

検索オプションのクラスSelectOptionsを使用することで、SELECT文が記述されたSQLファイルをベースにし、 ページング処理や悲観的排他制御用のSQLを自動で生成できます。

SelectOptionsは、複数件検索1件検索イテレーションによる検索と組み合わせて使用します。

SelectOptionsは、Daoのメソッドのパラメータとして定義します。

selectByDepartmentName(String departmentName, SelectOptions options); ... }]]>

SelectOptionsは、SelectOptionsのstaticなgetメソッドにより取得できます。

SelectOptionsoffsetメソッドで開始位置、limitメソッドで取得件数を指定し、 SelectOptionsのインスタンスをDaoのメソッドに渡します。

list = dao.selectByDepartmentName("ACCOUNT", options);]]>

ページングの制約

ページングは、ファイルに記述されているオリジナルのSQLを書き換え実行することで実現されています。 オリジナルのSQLは次の条件を満たしていなければいけません。

  • SELECT文である
  • 最上位のレベルでUNION、EXCEPT、INTERSECT等の集合演算を行っていない(サブクエリで利用している場合は可)
  • ページング処理を含んでいない

さらに、データベースの方言によっては特定の条件を満たしていなければいけません。

方言クラス条件
org.seasar.doma.jdbc.dialect.Db2Dialectoffsetを指定する場合、ORDER BY句を持ちORDER BY句で指定するカラムすべてをSELECT句に含んでいる。
org.seasar.doma.jdbc.dialect.Mssql2008Dialectoffsetを指定する場合、ORDER BY句を持ちORDER BY句で指定するカラムすべてをSELECT句に含んでいる。
org.seasar.doma.jdbc.dialect.StandardDialectORDER BY句を持ちORDER BY句で指定するカラムすべてをSELECT句に含んでいる。

SelectOptionsforUpdateメソッドで悲観的排他制御を行うことを指示し、 SelectOptionsのインスタンスをDaoのメソッドに渡します。

list = dao.selectByDepartmentName("ACCOUNT", options);]]>

SelectOptionsには、ロック対象のテーブルやカラムのエイリアスを指定できるforUpdateメソッドや、 ロックの取得を待機しないforUpdateNowaitなど、名前が「forUpdate」で始まる悲観的排他制御用のメソッドが用意されています。 詳しくはJavadocコメントを参照ください。

悲観的排他制御の制約

悲観的排他制御は、ファイルに記述されているオリジナルのSQLを書き換え実行することで実現されています。 オリジナルのSQLは次の条件を満たしていなければいけません。

  • SELECT文である
  • 最上位のレベルでUNION、EXCEPT、INTERSECT等の集合演算を行っていない(サブクエリで利用している場合は可)
  • 悲観的排他制御の処理を含んでいない

データベースの方言によっては、悲観的排他制御用のメソッドのすべてもしくは一部が使用できません。

方言クラス説明
org.seasar.doma.jdbc.dialect.Db2DialectforUpdate()を使用できる。
org.seasar.doma.jdbc.dialect.H2DialectforUpdate()を使用できる。
org.seasar.doma.jdbc.dialect.HsqldbDialectforUpdate()を使用できる。
org.seasar.doma.jdbc.dialect.Mssql2008DialectforUpdate()forUpdateNoWait()を使用できる。ただし、オリジナルのSQLのFROM句は1つのテーブルだけから成らねばならない。
org.seasar.doma.jdbc.dialect.MysqlDialectforUpdate()を使用できる。
org.seasar.doma.jdbc.dialect.OracleDialectforUpdate()forUpdate(String... aliases)forUpdateNowait()forUpdateNowait(String... aliases) forUpdateWait(int waitSeconds)forUpdateWait(int waitSeconds, String... aliases)を使用できる。
org.seasar.doma.jdbc.dialect.PostgresDialectforUpdate()forUpdate(String... aliases)を使用できる。
org.seasar.doma.jdbc.dialect.StandardDialect悲観的排他制御用のメソッドすべてを使用できない。

SelectOptionscountメソッドを呼び出すことで、集計件数を取得できるようになります。 通常、ページングのオプションと組み合わせて使用し、ページングで絞り込まない場合の全件数を取得する場合に使います。

list = dao.selectByDepartmentName("ACCOUNT", options); long count = options.getCount();]]>

集計件数は、Daoのメソッド呼出し後に、SelectOptionsgetCountメソッドを使って取得します。 メソッド呼び出しの前にcountメソッドを実行していない場合、getCountメソッドは-1を返します。

検索結果が1件以上存在することを保証したい場合は、@SelectensureResult要素にtrueを指定します。

検索結果が0件ならばorg.seasar.doma.jdbc.NoResultExceptionがスローされます。

検索結果を受ける型がエンティティクラスやエンティティクラスを要素とするjava.util.Listの場合において、エンティティのプロパティすべてに対して漏れなく結果セットのカラムをマッピングすることを保証したい場合は、@SelectensureResultMapping要素にtrueを指定します。

結果セットのカラムにマッピングされないプロパティが存在する場合org.seasar.doma.jdbc.ResultMappingExceptionがスローされます。

@SelectqueryTimeout要素にクエリタイムアウトの秒数を指定できます。

selectAll();]]>

queryTimeout要素に値を指定しない場合、 設定クラスに指定されたクエリタイムアウトが使用されます。

@SelectfetchSize要素にフェッチサイズを指定できます。

selectAll();]]>

fetchSize要素に値を指定しない場合、 設定クラスに指定されたフェッチサイズが使用されます。

@SelectmaxRows要素に最大行数を指定できます。

selectAll();]]>

maxRows要素に値を指定しない場合、 設定クラスに指定された最大行数が使用されます。

検索結果を]]>にマッピングする場合、 @SelectmapKeyNaming要素にマップのキーのネーミング規約を指定できます。

> selectAll();]]>

MapKeyNamingType.CAMEL_CASEは、カラム名をキャメルケースに変換することを示します。 そのほかに、カラム名を大文字や小文字に変換する規約があります。 指定しない場合、変換は行われません。