Open3
Doma の DAO スタイルと DSL スタイルの使い分け
Doma は2つのプログラミングスタイルを提供している。
- DAO スタイル: DAO のメソッドにアノテーションを付与し、SQL を自動生成させるか SQL を指定する方法
- DSL スタイル: Criteria API を使って Java コードで SQL を組み立てる方法
どう使い分けるかについては絶対の正解はないが、次のような基準で併用すると良いと思う。
- 単純な追加、更新、削除は DAO スタイル
- 単純な検索は DAO のデフォルトメソッドの中で DSL スタイル
- 複雑な検索は DAO スタイル
コード例は以下の通り。
@Dao
public interface EmployeeDao {
// ① 単純な追加、更新、削除などはアノテーションを付与して自動実行
@Update
int update(Employee employee);
// ② パラメータが少数かつ単純な検索は Criteria API を利用
default Employee selectById(int id) {
var e = new Employee_();
return QueryDsl.of(this).from(e).where(c -> c.eq(e.employeeId, id)).fetchOne();
}
// ③ パラメータが多数だが単純な検索は呼び出し元で Criteria API を利用
default List<Employee> select(Function<QueryDsl, List<Employee>> block) {
return block.apply(QueryDsl.of(this));
}
// ④ 複雑な検索は @Select アノテーションを付与して SQL ファイル か @Sql アノテーションを利用(ここでは SQL ファイルを利用)
@Select
List<Employee> selectWithComplexSql(int departmentId, Salary salary);
}
上記のコードを呼び出す例は次のようになる。
@Test
void test(Config config) {
EmployeeDao dao = new EmployeeDaoImpl(config);
// ②の実行
var employee = dao.selectById(1);
employee.setDepartmentId(2);
// ①の実行
dao.update(employee);
// ③の実行
var result =
dao.select(
dsl -> {
var e = new Employee_();
return dsl.from(e)
.where(
c -> {
c.eq(e.departmentId, 1);
c.ge(e.employeeNo, 1000);
c.between(e.salary, new Salary("1000"), new Salary("5000"));
})
.orderBy(c -> c.asc(e.employeeId))
.fetch();
});
System.out.println(result.size());
// ④の実行
var result2 = dao.selectWithComplexSql(1, new Salary("1000"));
System.out.println(result2.size());
}
③の方法を採用するかどうかは議論の余地はある。
引数を DAO メソッドへ渡す手間を避けられるが、②の方法に統一した方が実行されるクエリが DAO インタフェースに閉じるのでメンテナンス性は高いかもしれない。
②の方法は、④の方法に切り替えても呼び出し元のコードを一切影響を与えないという利点がある