DtoQuery
DtoQueryは、SQLを使用してプレーンビーンにマッピングする場合に使用します。これらのプレーンビーンは、パブリックコンストラクタとパブリックゲッター/セッターを持つ通常のビーンです。
public static class CustomerDto {
Integer id;
String name;
... // getters & setters
}
// using positioned parameters
List<CustomerDto> beans =
database.findDto(CustomerDto.class, "select id, name from customer where name = ?")
.setParameter(1, "Rob")
.findList();
// using named parameters
List<CustomerDto> beans =
database.findDto(CustomerDto.class, "select id, name from customer where name = :name")
.setParameter("name", "Rob")
.findList();
マッピング
SQL resultSetをDTOビーンにマッピングする際には、以下を使用します。
- まず、resultSetの列数と同じ数の引数を持つコンストラクタを探します。そのようなコンストラクタがあれば、それをマッピングに使用します(正しい型を想定)。
- 次に、resultSetの列数が最大のコンストラクタよりも多いかどうかを確認します。多い場合は、最大のコンストラクタを使用して最初の列を読み取り、次にセッターメソッドを使用して残りの列をマッピングします。
- 最後に、デフォルトコンストラクタとセッターメソッドを使用します。
リフレクションではなくMethodHandlesを使用してマッピングを実行することに注意してください。つまり、コンストラクタとセッターメソッドはパブリックアクセスである必要があります。
firstRow / maxRows
sqlクエリにfirstRows/maxRowsを適用できます。
String sql = "select id, name from customer where name like ?";
List<CustomerDto> robs = server().findDto(CustomerDto.class, sql)
.setParameter(1, "Rob%")
.setMaxRows(10)
.findList();
データベースプラットフォームに対してfirstRows/maxRowsを適用する適切なsqlが追加されます。
select id, name from o_customer where name like ?
limit 10
RelaxedMode
デフォルトでは、マッピングを実行するときに、列をプロパティ(セッターメソッド)にマッピングできない場合、例外がスローされます。
代わりに、query.setRelaxedMode()
を使用してクエリでリラックスモードを設定できます。これは、マッピングできない列を効果的に無視/スキップすることを意味します。
これは、潜在的に大規模な既存のクエリがあり、一部の列のみをビーンプロパティにマッピングしたい場合に役立つと予想されます。
Postgres ANY
Postgresを使用する場合は、位置パラメータを使用するか、setArrayParameter()
を使用することで、DtoQueryでPostgresのANY
を使用できます。
PostgresのANY
を使用する利点は、パラメータの数に関係なく、単一のSQLクエリを使用できることです。単一のJDBC PreparedStatementを使用し、データベースは解析するSQLクエリが1つだけになります。これにより、データベースのハードパースが減り、PreparedStatementキャッシュの利用効率が向上し、キャッシュするクエリプランが減り、消費されるメモリが少なくなります。
例:位置パラメータ
インデックス位置パラメータを使用し、JDBC ARRAYとしてバインドされるコレクションをバインドする場合。
List<Integer> ids = List.of(1, 2);
String sql = "select id, name from customer where id = any(?)"
List<CustomerDto> list = DB.findDto(CustomerDto.class, sql)
.setParameter(ids) // bind as JDBC ARRAY
.findList();
例:名前付きパラメータに対するsetArrayParameter()の使用
名前付きパラメータを使用する場合、デフォルトではEbeanはIN
句の使用を期待し、コレクションは「展開」されます。たとえば、3つの値のコレクションは、JDBCが単一のARRAYをバインドするのではなく、3つの個別のJDBCバインド値?,?,?
に展開されます。ANY
句に対してコレクションをPostgres ARRAYとしてバインドするには、setArrayParameter()
を使用する必要があります。
List<Integer> ids = List.of(1, 2);
String sql = "select id, name from o_customer where id = any(:idList)"
List<CustomerDto> list2 = DB.findDto(CustomerDto.class, sql)
.setArrayParameter("idList", ids) // bind as JDBC ARRAY
.findList();
findEach
大量のクエリを処理する際に、すべてのビーンをリストに保持せずに、1つずつ処理したい場合は、findEachを使用します。
String sql = "select id, name from o_customer where id > :id order by id desc";
database.findDto(CustomerDto.class, sql)
.setParameter("id", 0)
.findEach(customer -> {
log.debug("got " + customer.getId() + " " + customer.getName());
...
});
findStream
findStreamは、結果を1つずつ処理するという点でfindEachに似ています。基礎となるリソースが確実に閉じられるように、try with resources
ブロックを使用する必要があります。
String sql = "select id, name from o_customer where id > ? order by id desc";
try (Stream<CustomerDto> customers =
database.findDto(CustomerDto.class, sql)
.setParameter(0)
.findStream()) {
// use the stream of customers ...
...
}
findIterate
findIterateは、結果を1つずつ処理するという点でfindStreamとfindEachに似ています。基礎となるリソースが確実に閉じられるように、try with resources
ブロックを使用する必要があります。
String sql = "select id, name from o_customer where id > :id order by id desc";
try (QueryIterator<CustomerDto> customers =
database.findDto(CustomerDto.class, sql)
.setParameter(0)
.findIterate()) {
// iterate through the customers
...
}
単一列
単一列を選択する場合は、SqlQuery.mapToScalar()を使用することをお勧めします。
String sql = "select mysequence.nextval";
Long nextVal = DB.sqlQuery(sql)
.mapToScalar(Long.class)
.findOne();