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
firstRow
と maxRows
を指定すると、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 を使用すると、列がプロパティに自動的にマッピングされるため、シンプルで使いやすいため、エンティティ Bean
で SQL
クエリを実行する方法として、RawSql よりも推奨されます。
ただし、select 句に複数のテーブルの列を含めたい場合、findNative にはいくつかの制限があります(上記の制限事項を参照)。これらの制限に達した場合は、列をプロパティに明示的にマッピングする RawSql を使用する必要があります。