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/Dalのクラスの完全修飾名をディレクトリに変換したもの/Data Access Objectのメソッド名.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インタフェースのメソッドのパラメータが基本型もしくはドメインクラスの場合、 このパラメータは、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の例は次のとおりです。

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インジェクションを防ぐため、埋め込み変数の一部としてシングルクォテーション、セミコロン、行コメント、ブロックコメントは含めることは禁止しています。

埋め込み変数は/*#~*/というブロックコメントで示します。埋め込み変数の名前はメソッドのパラメータ名にマッピングされます。 埋め込み変数は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

WHEREHAVINGの自動除去

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

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

/*%if ~*/の前の whereは自動で除去されます。

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 は自動で除去されます。

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'/*%hasNext " or " */
/*%end*/

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

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

hasNext

/*%for 識別子 : 式*/ から /*%end*/ までの内側の/*%forhasNext 式*/は、 次の繰り返しが続く場合にのみ、式の評価結果を繰り返される文字列に連結することを示します。 式は、String、Character、charのいずれかの型として評価可能な式でなければいけません。

通常のブロックコメント

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

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

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

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

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

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

通常の行コメント

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

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

-- aaa

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

--elseif ~ --
--else
--hasNext ~ --

式言語

式コメントには式を記述できます。 文法は、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'

ここでは、@prefix(employee.employeeName) というように、 employee.employeeName@prefix関数に渡しています。 組み込み関数の名前はすべて@で始まります。 employee.employeeName の値が「ABC」である場合、 SQLにバインディングされる値は「ABC%」となります。 もし、employee.employeeName の値が「AB%C」というように「%」を含んでいる場合、 「%」はデフォルトのエスケープシーケンスでエスケープされ、SQLにバインディングされる値は「AB\%C%」となります。

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

戻り値の型 関数名とパラメータ 概要
String @prefix(String prefix) 前方一致検索を行うことを示します。戻り値は入力値をエスケープしワイルドカードを後ろに付与した文字列です。エスケープにはデフォルトのエスケープ文字を用いて行われます。
String @prefix(String prefix, char escape) 前方一致検索を行うことを示します。戻り値は入力値をエスケープしワイルドカードを後ろに付与した文字列です。エスケープは第2引数で指定したエスケープ文字を用いて行われます。
String @suffix(String suffix) 後方一致検索を行うことを示します。戻り値は入力値をエスケープしワイルドカードを前に付与した文字列です。エスケープはデフォルトのエスケープ文字を用いて行われます。
String @suffix(String suffix, char escape) 後方一致検索を行うことを示します。戻り値は入力値をエスケープしワイルドカードを前に付与した文字列です。エスケープは第2引数で指定したエスケープ文字を用いて行われます。
String @contain(String inside) 中間一致検索を行うことを示します。戻り値は入力値をエスケープしワイルドカードを前と後ろに付与した文字列です。エスケープはデフォルトのエスケープ文字を用いて行われます。
String @contain(String inside, char escape) 中間一致検索を行うことを示します。戻り値は入力値をエスケープしワイルドカードを前と後ろに付与した文字列です。エスケープは第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のメソッドに対応しています。