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();