About

ドキュメント

プロジェクト文書

Built by Maven

概要

SQLファイルは、SQL文を格納したテキストファイルで、Daoのメソッドにマッピングされます。 SQLのブロックコメント(/* */)や行コメント(--)を使用することで、バインド変数や動的なSQLのための条件分岐を表現できます。 SQLのツールでそのままそのSQLを実行できるように、バインド変数にはテスト用のデータを指定します。テスト用のデータは、実行時には使用されません。 たとえば、SQLファイルには次のようなSQL文が格納されます。

select * from employee where employee_id = /* employeeId */99

ここでは、ブロックコメントで囲まれた employeeIdがDaoインタフェースのメソッドのパラメータに対応し、 直後の 99はテスト用の条件になります。 対応するDaoインタフェースのメソッドは次のとおりです。

Employee selectById(employeeId);

SQLファイルにマッピングするためのアノテーション

SQLファイルとDaoのメソッドのマッピングは次のアノテーションで示します。

SQLファイル

配置場所

SQLファイルはクラスパスが通った META-INF ディレクトリ以下に配置しなければいけません。

ファイル名の形式

ファイル名は、次の形式でなければいけません。

META-INF/Daoのクラスの完全修飾名をディレクトリに変換したもの/Daoのメソッド名.sql

例えば、 Daoのクラスが aaa.bbb.EmployeeDaoで マッピングしたいメソッドが selectById の場合、パス名は次のようになります。

META-INF/aaa/bbb/EmployeeDao/selectById.sql

複数のRDBMSに対応する必要があり特定のRDBMSでは別のSQLファイルを使いたい場合、 .sql の前にハイフン区切りでRDBMS名を入れることで、優先的に使用するファイルを指示できます。 たとえば、PostgreSQL専用のSQLファイルは次の名前にします。

META-INF/aaa/bbb/EmployeeDao/selectById-postgres.sql

この場合、PostgreSQLを使用している場合に限り、META-INF/aaa/bbb/EmployeeDao/selectById.sql よりも META-INF/aaa/bbb/EmployeeDao/selectById-postgres.sql が優先的に使用されます。

RDBMS名は、 org.seasar.doma.jdbc.dialect.DialectgetNameメソッドの値が使用されます。

エンコーディング

SQLファイルのエンコーディングはUTF-8でなければいけません。

SQLコメント

Domaでは、SQLコメント中に式を記述することで、値のバインディングや条件分岐を行います。 Domaに解釈されるSQLコメントを式コメントと呼びます。

バインド変数コメント

バインド変数を示す式コメントをバインド変数コメントと呼びます。 バインド変数は、java.sql.PreparedStatementを介してSQLに設定されます。

バインド変数は/*~*/というブロックコメントで囲んで示します。 バインド変数の名前は、Daoメソッドのパラメータ名に対応します。 対応するパラメータの型は、基本型もしくはドメインクラスでなければいけません。 バインド変数コメントの直後にはテスト用データを指定する必要があります。 テスト用データは、実行時には使用されません。

単一のパラメータ

Daoインタフェースのメソッドのパラメータが基本型もしくはドメインクラスの場合、 このパラメータは、1つのバインド変数を表現できます。 バインド変数コメントはバインド変数を埋め込みたい場所に記述し、バインド変数コメントの直後にはテスト用データを指定しなければいけません。 Daoインタフェースのメソッドと、対応するSQLの例は次のとおりです。

List<Employee> selectById(Integer employeeId);
select * from employee where employee_id = /* employeeId */99

Listのパラメータ

Daoインタフェースのメソッドのパラメータがjava.util.Listの場合、 このパラメータは、IN句内の複数のバインド変数を表現できます。 バインド変数コメントはINキーワードの直後に置き、バインド変数コメントの直後には括弧つきでテスト用データを指定しなければいけません。 Daoインタフェースのメソッドと、対応するSQLの例は次のとおりです。

List<Employee> selectByIdList(List<Integer> employeeIdList);
select * from employee where employee_id in /* employeeIdList */(1,2,3)

エンティティクラスのパラメータ

Daoインタフェースのメソッドのパラメータがエンティティクラスの場合、 エンティティクラスのパラメータは、複数のバインド変数コメントに対応します。 バインド変数コメントの中では、ドット(.)を使用しエンティティのフィールドにアクセスできます。 Daoインタフェースのメソッドと、対応するSQLの例は次のとおりです。 Employeeクラスには、employeeNameフィールドやsalaryフィールドが存在するものとします。

List<Employee> selectByNameAndSalary(Employee employee);
select * from employee
where
employee_name = /* employee.employeeName */'abc' 
and
salary = /* employee.salary */1234

フィールドにアクセスする代わりに、publicなメソッドを呼び出すことも可能です。

select * from employee
where
salary = /* employee.getTaxedSalary() */1234

埋め込み変数コメント

埋め込み変数を示す式コメントを埋め込み変数コメントと呼びます。 埋め込み変数の値は、SQLを組み立てる際にSQLの一部として直接埋め込まれます。 SQLインジェクションを防ぐため、埋め込み変数の値にシングルクォテーション、セミコロン、行コメント、ブロックコメントは含めることは禁止しています。

埋め込み変数は/*#~*/というブロックコメントで示します。埋め込み変数の名前はDaoメソッドのパラメータ名にマッピングされます。 埋め込み変数はORDER BY句など、SQLの一部をプログラムで組み立てたい場合に使用できます。 Daoのメソッドと、対応するSQLの例は次のとおりです。

List<Employee> selectAll(BigDecimal salary, String orderyBy);
select * from employee where salary > /* salary */100 /*# orderBy */

Daoの呼び出し例は次の通りです。

EmployeeDao dao = new EmployeeDaoImpl();
BigDecimal salary = new BigDecimal(1000);
String orderBy = "order by salary asc, employee_name";
List<Employee> list = dao.selectAll(salary, orderBy);

発行されるSQLは次のようになります。

select * from employee where salary > ? order by salary asc, employee_name

条件コメント

ifend

条件分岐を示す式コメントを条件コメントと呼びます。 構文は、次のとおりです。

/*%if 条件式*/ ~ /*%end*/
条件式は、結果がbooleanもしくはjava.lang.Boolean型と評価される式でなければいけません。 例を示します。

select * from employee where 
/*%if employeeId != null */
    employee_id = /*employeeId*/99
/*%end*/

上記のSQL文は、 employeeIdnullでない場合 次のような準備された文に変換されます。

select * from employee where employee_id = ?

このSQL文は、 employeeIdnullの場合に次のような準備された文に変換されます。

select * from employee

ifの条件が成り立たない場合にifの外にあるWHERE句が出力されないのは、下記に述べるようにWHEREHAVINGの自動除去機能が働いているためです。

WHEREHAVINGの自動除去

条件コメントを使用した場合、条件の前にあるWHEREやHAVINGについて、自動で出力の要/不要を判定します。 たとえば、次のようなSQLでemployeeIdnullの場合、

select * from employee where 
/*%if employeeId != null */
    employee_id = /* employeeId */99
/*%end*/

/*%if ~*/の前の whereは自動で除去され、次のSQLが生成されます。

select * from employee

ANDORの自動除去

条件コメントを使用した場合、条件の後ろにつづくANDやORについて、自動で出力の要/不要を判定します。 たとえば、次のようなSQLでemployeeIdnullの場合、

select * from employee where 
/*%if employeeId != null */
    employee_id = /* employeeId */99
/*%end*/
and employeeName like 's%'

/*%end*/の後ろの and は自動で除去され、次のSQLが生成されます。

select * from employee where employeeName like 's%'

elseifelse

/*%if 条件式*//*%end*/ の間では、 行コメントを使用した次の構文も使用できます。

--elseif 条件式--
--else

例を示します。

select * from employee where 
/*%if employeeId != null */   employee_id = /* employeeId */99
--elseif employeeId == 999-- department_id is null
--else                       employee_id is null
/*%end*/

ネストした条件コメント

条件コメントはネストさせることができます。

select * from employee where 
/*%if employeeId != null */
  employee_id = /* employeeId */99
  /*%if employeeName != null */ 
    and employee_name = /* employeeName */'hoge'
  /*%end*/
/*%end*/

繰り返しコメント

forend

繰り返しを示す式コメントを繰り返しコメントと呼びます。 構文は、次のとおりです。

/*%for 識別子 : 式*/ ~ /*%end*/
識別子は、繰り返される要素を指す変数です。 式は、java.lang.Iterable型として評価される式でなければいけません。

例を示します。

select * from employee where
/*%for name : names */
employee_name like /* name */'hoge'
  /*%if name_has_next */
/*# "or" */
  /*%end */
/*%end*/

上記のSQL文は、namesが3つの要素からなるリストを表す場合、次のような準備された文に変換されます。

select * from employee where
employee_name like ? 
or
employee_name like ?
or
employee_name like ?

item_has_nextとitem_index

/*%for 識別子 : 式*/ から /*%end*/ までの内側では、次の2つの特別な変数を使用できます。

  • item_has_next
  • item_index

itemは識別子です。つまり、forの識別子が「name」の場合、この変数はそれぞれ「name_has_next」と「name_index」となります。 この変数は、次の繰り返しが可能かどうかを示します。

item_has_nextは、次の繰り返し要素が存在するかどうかを示すbooleanの値です。

item_indexは、次の繰り返しのindexを表すintの値です。値は0始まりです。

WHEREHAVINGの自動除去

繰り返しコメントを使用した場合、コメントの前にあるWHEREやHAVINGについて、自動で出力の要/不要を判定します。 たとえば、次のようなSQLでnamesのsizeが0の場合(繰り返しが行われない場合)、

select * from employee where 
/*%for name : names */
employee_name like /* name */'hoge'
  /*%if name_has_next */
/*# "or" */
  /*%end */
/*%end*/

/*%for ~*/の前の whereは自動で除去され、次のSQLが生成されます。

select * from employee

ANDORの自動除去

繰り返しコメントを使用した場合、コメントの後ろにつづくANDやORについて、自動で出力の要/不要を判定します。 たとえば、次のようなSQLでnamesのsizeが0の場合(繰り返しが行われない場合)、

select * from employee where 
/*%for name : names */
employee_name like /* name */'hoge'
  /*%if name_has_next */
/*# "or" */
  /*%end */
/*%end*/
or
salary > 1000

/*%end*/の後ろの or は自動で除去され、次のSQLが生成されます。

select * from employee where salary > 1000

通常のブロックコメント

/*の直後に続く3文字目が次のような値の場合、それは通常のブロックコメントだとみなされます。

  • Javaの識別子の先頭で使用できない文字(ただし、空白と式で特別意味をもつ「%」、「#」、「@」、「"」、「'」は除く)

たとえば、次の例はすべて通常のブロックコメントとみなされます。

/**~*/
/*+~*/
/*=~*/
/*:~*/
/*;~*/
/*(~*/
/*)~*/
/*&~*/

一方、次の例はすべて式コメントだとみなされます。

/* ~*/ ...--3文字目が空白であるため式コメントです。
/*a~*/ ...--3文字目がJavaの識別子の先頭で使用可能な文字であるため式コメントです。
/*$~*/ ...--3文字目がJavaの識別子の先頭で使用可能な文字であるため式コメントです。
/*%~*/ ...--3文字目が条件コメントを表す「%」であるため式コメントです。
/*#~*/ ...--3文字目が埋め込み変数コメントを表す「#」であるため式コメントです。
/*@~*/ ...--3文字目が組み込み関数もしくはクラス名を表す「@」であるため式コメントです。

通常の行コメント

--の直後に、elseifelseがつづかない場合、それは通常の行コメントだとみなされます。

たとえば、次の例は通常の行コメントだとみなされます。

-- aaa

一方、次の例はすべて式コメントだとみなされます。

--elseif ~ --
--else

式言語

式コメントには式を記述できます。 文法は、Javaとほとんど同じです。 ただし、Javaで可能なことすべてができるわけではありません。

リテラル

以下のリテラルが用意されています。

リテラル
null void
true boolean
false boolean
10 int
10L long
0.123F float
0.123D double
0.123B java.math.BigDecimal
'a' char
"a" String

数値の型は、リテラルの最後に「L」や「F」などを付与して区別します。 「L」や「F」などは大文字でなければいけません。

select * from employee where 
/*%if employeeName != null && employeeName.length() > 10 */
    employee_name = /*employeeName*/'smith'
/*%end*/

比較演算子

以下の比較演算子を使用できます。

比較演算子
==
!=
<
<=
>
>=

比較演算子を利用するには、 被演算子が java.lang.Comparableを実装している必要があります。

<<=>>=では、 非演算子にnullであってはいけません。

select * from employee where 
/*%if employeeName.indexOf("s") > -1 */
    employee_name = /* employeeName */'smith'
/*%end*/

論理演算子

以下の論理演算子を使用できます。

論理演算子
!
&&
||

括弧を使って、演算子が適用される優先度を制御できます。

select * from employee where 
/*%if (departmentId == null || managerId == null) and employee_name != null */
    employee_name = /* employeeName */'smith'
/*%end*/

算術演算子

以下の算術演算子を使用できます。

算術演算子
+
-
*
/
%

被演算子は数値型でなければいけません。

select * from employee where 
    salary = /* salary + 1000 */0

その他の演算子

+演算子を使って文字を連結できます。

被演算子は次のいずれかの型でなければいけません。

  • java.lang.String
  • java.lang.Character
  • char
select * from employee where 
   employee_name like /* employeeName + "_" */'smith'

インスタンスメソッドの呼び出し

ドット(.)で区切ってメソッド名を指定することでインスタンスメソッドを実行可能です。 実行可能なメソッドは、可視性がpublicなものだけに限られます。

select * from employee where 
/*%if employeeName.startsWith("s") */
    employee_name = /* employeeName */'smith'
/*%end*/

引数がない場合は、メソッド名の後ろに()を指定します。

select * from employee where 
/*%if employeeName.length() > 10 */ 
    employee_name = /* employeeName */'smith'
/*%end*/

インスタンスフィールドへのアクセス

ドット(.)で区切ってフィールド名を指定することでインスタンスフィールドにアクセスできます。 可視性はprivateであってもアクセス可能です。

select * from employee where 
    employee_name = /* employee.employeeName */'smith'

staticメソッドの呼び出し

@で囲まれたクラスの完全修飾名にメソッドを続けることでstaticメソッドを実行可能です。 実行可能なメソッドは、可視性がpublicなものだけに限られます。

select * from employee where 
/*%if @java.util.regex.Pattern@matches("^[a-z]*$", employeeName) */
    employee_name = /* employeeName */'smith'
/*%end*/

staticフィールドへのアクセス

@で囲まれたクラスの完全修飾名にフィールドを続けることでstaticフィールドにアクセスできます。 可視性はprivateであってもアクセス可能です。

select * from employee where 
/*%if employeeName.lenght() < @java.lang.Byte@MAX_VALUE */
    employee_name = /* employeeName */'smith'
/*%end*/

組み込み関数の使用

組み込み関数は、主に、SQLにバインドする前にバインド変数の値を変更するためのユーティリティです。

たとえば、likeで前方一致検索を行う場合に、次のように記述できます。

select * from employee where 
    employee_name like /* @prefix(employee.employeeName) */'smith' escape '$'

ここでは、@prefix(employee.employeeName) というように、 employee.employeeName@prefix関数に渡しています。 @prefix関数は、パラメータで受け取る文字列を前方一致検索用の文字列に変換します。また、特別な意味を持つ文字をエスケープします。 この例では、employee.employeeName の値が「ABC」である場合、 値は「ABC%」に変換されます。 もし、employee.employeeName の値が「AB%C」というように「%」を含んでいる場合、 「%」はデフォルトのエスケープシーケンス($)でエスケープされ、値は「AB$%C%」に変換されます。

使用可能な関数は以下のとおりです。デフォルトでは、いずれの関数も最初の引数にnullを渡した場合、nullを返します。

戻り値の型 関数名とパラメータ 概要
String @escape(String prefix) LIKE演算のためのエスケープを行うことを示します。戻り値は入力値をエスケープした文字列です。エスケープにはデフォルトのエスケープ文字($)を用いて行われます。
String @escape(String prefix, char escapeChar) LIKE演算のためのエスケープを行うことを示します。戻り値は入力値をエスケープした文字列です。エスケープは第2引数で指定したエスケープ文字を用いて行われます。
String @prefix(String prefix) 前方一致検索を行うことを示します。戻り値は入力値をエスケープしワイルドカードを後ろに付与した文字列です。エスケープにはデフォルトのエスケープ文字($)を用いて行われます。
String @prefix(String prefix, char escapeChar) 前方一致検索を行うことを示します。戻り値は入力値をエスケープしワイルドカードを後ろに付与した文字列です。エスケープは第2引数で指定したエスケープ文字を用いて行われます。
String @suffix(String suffix) 後方一致検索を行うことを示します。戻り値は入力値をエスケープしワイルドカードを前に付与した文字列です。エスケープはデフォルトのエスケープ文字($)を用いて行われます。
String @suffix(String suffix, char escapeChar) 後方一致検索を行うことを示します。戻り値は入力値をエスケープしワイルドカードを前に付与した文字列です。エスケープは第2引数で指定したエスケープ文字を用いて行われます。
String @contain(String inside) 中間一致検索を行うことを示します。戻り値は入力値をエスケープしワイルドカードを前と後ろに付与した文字列です。エスケープはデフォルトのエスケープ文字($)を用いて行われます。
String @contain(String inside, char escapeChar) 中間一致検索を行うことを示します。戻り値は入力値をエスケープしワイルドカードを前と後ろに付与した文字列です。エスケープは第2引数で指定したエスケープ文字を用いて行われます。
java.sql.Date @roundDownTimePart(java.sql.Date date) 時刻部分を切り捨てることを示します。戻り値は時刻部分が切り捨てられた新しい日付です。
java.sql.Timestamp @roundDownTimePart(java.sql.Timestamp timestamp) 時刻部分を切り捨てることを示します。戻り値は時刻部分が切り捨てられた新しいタイムスタンプです。
java.sql.Date @roundUpTimePart(java.sql.Date date) 時刻部分を切り上げることを示します。戻り値は時刻部分が切り上げられた新しい日付です。
java.sql.Timestamp @roundUpTimePart(java.sql.Timestamp timestamp) 時刻部分を切り上げることを示します。戻り値は時刻部分が切り上げられた新しいタイムスタンプです。

これらの関数は、org.seasar.doma.expr.ExpressionFunctionsのメソッドに対応しています。