はじめに
Doma は Java 17 以上で動作するデータベースアクセスフレームワークです。JDBCドライバが提供されるデータベース、主なものでいえば、MySQL、PosgreSQL、Microsoft SQL Sever、H2 Database のようなデータベースにアクセスできます。
Doma には、型安全に SQL を組み立てるための API、Criteira API があります。この記事では、Doma のバージョン3.6.0 に基づいて Criteria API を紹介します。
Doma入門 の他の記事もお読みください。
Doma の Criteria API には旧い Classic Criteria API と新しい Unified Criteria API の 2 種類があります。ここでは、Unified Criteria API を紹介します。
エンティティクラスの定義
次のようなデータベーススキーマがあるとします。
create table employee (
id integer not null primary key,
name varchar(255) not null,
age integer not null,
version integer not null);
上記のテーブルに対応するエンティティクラスは次のように定義できます。
@Entity(metamodel = @Metamodel)
public class Employee {
@Id
public Integer id;
public String name;
public Integer age;
@Version public Integer version;
}
一見、通常のエンティティクラスの定義ですが、@Entity
の宣言に metamodel = @Metamodel
という記述があることに注目してください。この記述がすごく重要で、適切な設定でコンパイルすることでEmployeeクラスと同じパッケージに Employee_
というメタモデルクラスが生成されるようになります。
メモモデルクラスの中身
わかりやすさのために少し省略しますが、メタモデルクラスの Employee_
は大体次のようなコードになります。
public final class Employee_ implements EntityMetamodel<Employee> {
public final PropertyMetamodel<java.lang.Integer> id = ...;
public final PropertyMetamodel<java.lang.String> name = ...;
public final PropertyMetamodel<java.lang.Integer> age = ...;
public final PropertyMetamodel<java.lang.Integer> version = ...;
}
このメタモデルクラスのポイントは、id
、name
、age
、version
のようにエンティティクラスのプロパティと同じ名前のプロパティを持っているということです。また、エンティティクラスにおけるプロパティの型情報を持っています。
これ以降は、このメタモデルクラスと Criteria API を使って実際に SQL を組み立てる例を示します。
Criteria API の利用
Criteria API はどこでも利用できますが、例えば Repository クラスや Doma の DAO インタフェースのデフォルトメソッドの中で利用するとわかりやすいでしょう。
Repositoryを使う場合
public class EmployeeRepository {
private final QueryDsl queryDsl;
public EmployeeRepository(Config config) {
this.queryDsl = new QueryDsl(config);
}
public Employee selectById(Integer id) {
// メタモデルの生成
var e = new Employee_();
// メタモデルを使ってSQLを組み立て結果を取得
return queryDsl.from(e).where(c -> c.eq(e.id, id)).fetchOne();
}
}
DAOを使う場合
@Dao
public interface EmployeeDao {
default Employee selectById(Integer id) {
// メタモデルの生成
var e = new Employee_();
// メタモデルを使ってSQLを組み立て結果を取得
return QueryDsl.of(this).from(e).where(c -> c.eq(e.id, id)).fetchOne();
}
}
selectById
メソッドの中身が Criteria API の利用例です。このメソッドではメタモデルクラスと Criteria API のエントリーポイントである QueryDsl
クラスを使ってSQLを組み立て実行結果を 1 つのエンティティとして取得しています。
組み立てられるSQLは次のようなものになります。
select t0_.id, t0_.name, t0_.age, t0_.version from Employee t0_ where t0_.id = ?
型安全の観点で言うと、 WHERE 句を組み立てる where(c -> c.eq(e.id, id))
の中の eq
メソッドがポイントです。このメソッドはジェネリクスを活用し、第1引数の型から第2引数の型をコンパイル時に決定しています。
つまり、この例では、 eq
メソッドの第1引数にメタモデルクラスの Integer
型を表すプロパティを渡すことで第2引数の型を Integer
型に決定しています。したがって、例えば、 c.eq(e.id, "String value")
のように第2引数に誤った型を渡してしまうこと(結果として実行時にエラーを発生させること)を防いでいます。
おわりに
エンティティを取得する例を使って、 Doma の Criteri API により型安全に SQL を組み立てられることを示しました。
ここで示したコードと同等のものは、下記のプロジェクトから入手できます。