findNative

findNative を使用すると、SQL を指定できます。 SQL には、? のような位置パラメータ、または :foo のような名前付きパラメータを含めることができます。

例 - 位置パラメータ
String sql = "select id, name from customer where name like ?";

Customer customer = DB.findNative(Customer.class, sql)
    .setParameter("Jo%")
    .findOne();
例 - 名前付きパラメータ
String sql = "select id, name from customer where name like :name order by name desc";

List<Customer> customers = DB.findNative(Customer.class, sql)
    .setParameter("name", "Jo%")
    .findList();

findNative を使用すると、列は Bean プロパティに自動的にマッピングされます。

上記の例では、**一部の**列を選択しているため、**部分的に値が設定されたエンティティ Bean** が取得されます(これは、必要なものだけを DB からフェッチする必要があるため、適切です)。

すべての列が必要な場合は select * を使用できますが、一般的にはお勧めしません。

例 - select *
String sql = "select * from customer where name like :name order by name desc";

List<Customer> customers = DB.findNative(Customer.class, sql)
    .setParameter("name", "Jo%")
    .findList();

列マッピング

列マッピングの仕組みは、クエリが最初に実行されるときに、resultSet 内の列の JDBC メタデータが読み取られ、これらの列が命名規則を使用して Bean プロパティに自動的にマッピングされることです。

これは、クエリの最初の実行に対してのみ行う必要があります。クエリが Bean にどのようにマッピングされるかはキャッシュされるため、クエリごとに JDBC resultSet メタデータを読み取る必要があるのは 1 回だけです。

命名規則に準拠していない列の場合は、SQL 列のエイリアスを使用します。

例 - 列エイリアス
// using sql column alias
String sql = "select id, fname as first_name, lname as last_name " +
             "from contact where lname like ?";

List<Contact> contacts = DB.findNative(Contact.class, sql)
  .setParameter(1, "B%")
  .findList();

マッピングされていない列

order by 句で、Bean プロパティにマッピングできない resultSet の列を指定する場合があります。この場合、これらのプロパティは無視されます。

例 - order by のマッピングされていない列
String sql = "select id, name, " +
  "case when anniversary >= ? then 1 when anniversary < ? then 2 end as order_column_1 " +
  "from o_customer " +
  "order by order_column_1";

List<Customer> result = DB.findNative(Customer.class, sql)
  .setParameter(LocalDate.now())
  .setParameter(LocalDate.now())
  .findList();

firstRow / maxRows

firstRowmaxRows を指定すると、limit/offset または同等の句を使用して SQL が適切に変更されます。

例 - maxRows の使用
String sql = "select id, name from o_customer order by name, id";

List<Customer> result = DB.findNative(Customer.class, sql)
  .setMaxRows(50)
  .findList();

fetchQuery

findNative を使用する場合、効果的に「ルート」または「起点」クエリの SQL を指定していると考えることができ、fetchQuery を使用してグラフの他の部分をさらにフェッチできます。

以下の例では、指定された SQL で findNative を使用して顧客をフェッチし、さらに fetchQuery を使用して、それらの顧客に関連する注文と連絡先をフェッチしています。

例 - fetchQuery の使用
List<Customer> result = DB.findNative(Customer.class, sql)
  .fetchQuery("orders")
  .fetchQuery("contacts")
  .findList();

複数テーブル

Oracle を除く(以下の Oracle の制限を参照)、SQL は複数のテーブルから選択でき、これらは関連するエンティティ Bean に自動的にマッピングできます。

たとえば、Contact と Customer のような 2 つの関連する Bean をフェッチして設定できます。返される連絡先エンティティ Bean には、顧客 ID と名前が設定された顧客 Bean が含まれます。

例 - 連絡先とそれに関連付けられた顧客
// Contacts + Customer
String sql
  = "select con.id, con.first_name, con.last_name, cust.id, cust.name " +
   " from contact con " +
   " join customer cust on cust.id = con.customer_id " +
   " order by con.first_name desc";

List<Contact> contacts = DB.findNative(Contact.class, sql)
    .findList();
例 - 注文明細行とそれに関連付けられた製品
String sql = "select line.*, p.* " +
  " from order_line line " +
  " join product p on p.id = line.product_id " +
  " where line.order_id = ?";

List<OrderLine> lines = DB.findNative(OrderLine.class, sql)
  .setParameter(order.getId())
  .findList();

制限事項

findNative を使用する際の制限(Oracle を除く)は、特定のテーブルのパスが**一意**である場合にのみ複数のテーブルをマッピングできることです。

たとえば、請求先住所と配送先住所の両方を同じ住所テーブルにマッピングする Customer があるとしましょう。ebean が住所テーブルの列をマッピングしようとすると、列がどのパス(billingAddress または shippingAddress)にマッピングされるかがわかりません。

この制限に達した場合は、列を Bean のパス/プロパティに明示的にマッピングできる RawSql を代わりに使用する必要があります。

Oracle の制限

Oracle JDBC ドライバーには、メタデータに現在列が関連するテーブルが含まれていないという制限があります。これは、Oracle では単一のテーブルのみをマッピングでき、複数のテーブルをマッピングできないことを意味します(代わりに RawSql を使用する必要があります)。

RawSql

findNative を使用すると、列がプロパティに自動的にマッピングされるため、シンプルで使いやすいため、エンティティ BeanSQL クエリを実行する方法として、RawSql よりも推奨されます。

ただし、select 句に複数のテーブルの列を含めたい場合、findNative にはいくつかの制限があります(上記の制限事項を参照)。これらの制限に達した場合は、列をプロパティに明示的にマッピングする RawSql を使用する必要があります。