ネイティブSQL - 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を使用すると、列は自動的にビーンのプロパティにマッピングされます。
上記の例では、いくつかの列を選択しており、その結果、**部分的にデータが設定されたエンティティビーン**を取得しています(これは良いことです。必要なものだけを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メタデータが読み取られ、これらの列が命名規則を使用してビーンのプロパティに自動的にマッピングされることです。
これは、クエリの初回実行に対してのみ行う必要があります。クエリがビーンにどのようにマッピングされるかはキャッシュされるため、クエリごとに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
句で、ビーンのプロパティにマッピングできない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は複数のテーブルから選択でき、これらは関連するエンティティビーンに自動的にマッピングできます。
たとえば、ContactとCustomerという2つの関連ビーンをフェッチして設定できます。返される連絡先エンティティビーンには、顧客IDと名前が設定された顧客ビーンが含まれます。
例 - 連絡先とその関連する顧客
// 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が住所テーブルの列をマッピングしようとすると、列がどのパス(請求先住所または配送先住所)にマッピングされているかがわかりません。
この制限に遭遇した場合は、列をビーンのパス/プロパティに明示的にマッピングできるRawSqlを使用する必要があります。
Oracleの制限事項
Oracle JDBCドライバには、メタデータに現在、列が関連するテーブルが含まれていないという制限があります。つまり、Oracleでは、単一のテーブルのみをマッピングでき、複数のテーブルをマッピングできません(代わりにRawSqlを使用する必要があります)。
RawSql
列が自動的にプロパティにマッピングされるため、エンティティビーン
でSQL
クエリを実行する方法として、RawSqlよりもfindNativeを使用することをお勧めします。
ただし、select句に複数のテーブルからの列を含めたい場合、findNativeにはいくつかの制限があります(上記の制限を参照)。これらの制限に遭遇した場合は、列をプロパティに明示的にマッピングするRawSqlを使用する必要があります。