8.16.2 ネイティブクエリでのデータベースの参照および更新方法
CJPAプロバイダでは,JPQL以外のクエリ言語として,データベース固有のネイティブクエリを直接記述して,データベースの参照・更新などを実行できます。
ここでは,ネイティブクエリでの使用方法について説明します。
(1) Queryオブジェクトの取得方法
ネイティブクエリを使用してQueryオブジェクトを取得するためには,次に示すCJPAプロバイダが提供するEntityManagerインタフェースのメソッドを使用します。
(a) Query createNativeQuery(String SQL文)
createNativeQueryの記述例を次に示します。引数には実行するネイティブクエリを指定します。
Query q = em.createNativeQuery( "SELECT o.id, o.quantity, o.item " + "FROM Order o, Item i " + "WHERE (o.item = i.id) AND (i.name = 'widget')");
(b) Query createNativeQuery(String SQL文,Class 結果格納クラス)
createNativeQueryの記述例を次に示します。第1引数には実行するネイティブクエリ,第2引数には実行結果を格納するクラスオブジェクトを指定します。
Query q = em.createNativeQuery( "SELECT o.id, o.quantity, o.item " + "FROM Order o, Item i " + "WHERE (o.item = i.id) AND (i.name = 'book')", com.hitachi.Order.class);
この例の場合,クエリが実行されると「book」という名前のアイテムに対するすべてのOrderエンティティのコレクションを返します。
なお,SELECT節で指定したクエリの結果と引数に指定したクラスオブジェクトの整合性がない場合は例外が発生します。
(c) Query createNativeQuery(String SQL文,String 結果セットマッピング名)
第1引数には実行するネイティブクエリ,第2引数には実行結果を格納する結果セットマッピング名を指定します。結果セットマッピングは,@ SqlResultSetMappingで指定します。なお,結果セットマッピングについては,「(2) 結果セットマッピング」を参照してください。
@SqlResultSetMappingの定義例とcreateNativeQueryの記述例を次に示します。
-
@SqlResultSetMappingの定義例
@SqlResultSetMapping(name="BookOrderResults", entities=@EntityResult(entityClass=com.hitachi.Order.class))
-
createNativeQueryの記述例
Query q = em.createNativeQuery( "SELECT o.id, o.quantity, o.item " + "FROM Order o, Item i " + "WHERE (o.item = i.id) AND (i.name = 'book')", "BookOrderResults");
この例の場合,クエリが実行されると「book」という名前のアイテムに対するすべてのOrderエンティティのコレクションを返します。@SqlResultSetMappingを使用することで,「8.16.1(1) Queryオブジェクトの取得方法」の@NamedQueryを使用した場合の記述例と同じ結果を得ることができます。
なお,SELECT節で指定したクエリ結果と引数に指定した@SqlResultSetMapping設定の整合性がない場合は例外が発生します。
(d) Query createNamedQuery(String クエリ名)
ネイティブクエリの場合も,JPQLと同じようにcreateNamedQueryメソッドを使用できます。ネイティブクエリの場合は,引数に名前付きネイティブクエリ名を指定してください。
名前付きネイティブクエリは,@NamedNativeQueryを任意のエンティティクラスに付与して定義します。引数のクエリ名には,@NamedNativeQueryのname属性で指定した名前を使用します。
CJPAプロバイダの場合,同じ名称の名前付きクエリを複数指定することはできません。同じ名称の名前付きクエリを複数指定した場合には,警告メッセージKDJE55522-Wを出力します。CJPAプロバイダで指定した場合,どのクエリが動作するかは保証しません。
次に,createNamedQueryメソッドの使用例を示します。この例では,@NamedNativeQueryを使用してあらかじめfindBookOrderという名前でクエリを登録しています。アプリケーションのcreateNamedQueryメソッドに登録した名前付きクエリ名を渡すことで,事前に登録されているクエリを取得して利用します。
-
@NamedNativeQueryでのクエリ名の登録
@NamedNativeQuery( name="findBookOrder", query="SELECT o.id, o.quantity, o.item " +" "FROM Order o, Item i " + "WHERE (o.item = i.id) AND (i.name = 'book')") ) @Entity public class Order { ・・・ }
-
createNamedQueryメソッドでの名前付きネイティブクエリの記述例
@Stateless public class MySessionBean { ・・・ @PersistenceContext public EntityManager em; ・・・ public void doSomething() { ・・・ Query q = em.createNamedQuery("findBookOrder ") } }
なお,同一の永続化ユニット内では,ほかのエンティティで定義した名前付きネイティブクエリを使用することもできます。
(2) 結果セットマッピング
結果セットマッピングとは,ネイティブクエリの実行結果を任意のエンティティクラスにマッピングして受け取ったり,スカラ値で受け取ったりするための機能です。
結果セットマッピングでは,ネイティブクエリの実行結果として取得した各カラム値のマッピング情報を@SqlResultSetMappingを指定して任意のエンティティクラスに対して付与します。
(a) @SqlResultSetMappingの記述形式
@SqlResultSetMappingの記述形式を次に示します。
@SqlResultSetMapping( name= 結果セットマッピングの名前, entities= 結果をマッピングするためのエンティティクラス指定(@EntityResultの配列), columns= 結果をマッピングするためのカラム指定(@ColumnResultの配列) )
- name属性
-
結果セットマッピング名を指定します。
- entities属性
-
@EntityResultの配列を指定します。@EntityResultの記述形式を次に示します。
@EntityResult( entityClass= 結果をマッピングするためのクラスを指定, fields= 結果をマッピングするためのフィールド指定(@FieldResultの配列) )
@EntityResultのentityClass属性には,カラム値を格納するエンティティクラスを指定します。また,field属性には,@FieldResultの配列を指定します。
@EntityResultの記述形式を次に示します。
@FiledResult( name= クラスの永続プロパティ(またはフィールド)の名前, column= SELECT節のカラムの名前(または別名) )
@FieldResultのname属性には,@EntityResultのentityClass属性に指定したエンティティクラスの永続化フィールド名を指定します。また,column属性にはカラム名を指定します。
- columns属性
-
columns属性は,エンティティクラスに格納しないでスカラ値として受け取るために,@ColumnResultの配列を指定します。スカラ値を取り出す必要がない場合は指定する必要はありません。@ColumnResultのname属性には,値を取り出すカラム名を指定してください。@ColumnResultの記述形式を次に示します。
@ColumnResult( name= SELECT節のカラムの名前(または別名) )
なお,カラム名はASで指定したエリアス名でも指定できます。SELECT節に同じ名前の複数の列を含む場合は,列の別名を使用してください。
(b) 使用例
従業員テーブル(Employee)と部門テーブル(Department)から従業員番号12003のクエリ結果を任意のエンティティクラス(EmployeeSetmap)にマッピングして,スカラ値(EMP_MONTHLY_SALARYカラム)を受け取る例を次に示します。
結果セットマッピング名(NativeQuerySetMap)をcreateNativeQueryの第2引数に指定して,結果セットマッピングを実行します。
-
結果セットマッピングを使用したネイティブクエリの記述例
query = em.createNativeQuery( "SELECT e.EMPLOYEE_ID AS EMP_EMPLOYEE_ID, " + "e.EMPLOYEE_NAME AS EMP_EMPLOYEE_NAME, " + "d.DEPARTMENT_NAME AS DEP_DEPARTMENT_NAME, " + "e.MONTHLY_SALARY AS EMP_MONTHLY_SALARY " + "FROM EMPLOYEE e, DEPARTMENT d " + "WHERE e.DEPARTMENT_ID = d.DEPARTMENT_ID " + "AND e.EMPLOYEE_ID = 12003", "NativeQuerySetMap");
-
ネイティブクエリの実行結果を格納する任意のエンティティクラス
@Entity public class EmployeeSetmap implements Serializable { : @Id public int getEmployeeId() { return employeeId; } public String getEmployeeName() { return employeeName; } public String getDepartmentName() { return departmentName; } : }
-
@ SqlResultSetMappingの記述例
@SqlResultSetMapping( name="NativeQuerySetmap", entities={ @EntityResult( entityClass=EmployeeSetmap.class, fields={ @FiledResult( name="employeeId", column="EMP_EMPLOYEE_ID"), @FiledResult( name="employeeName", column="EMP_EMPLOYEE_NAME"), @FiledResult( name="departmentName", column="DEP_DEPARTMENT_NAME") } ) }, columns={ @ColumnResult( name="EMP_MONTHLY_SALARY") }
なお,@ SqlResultSetMappingを実行してネイティブクエリを実行した結果のObject型配列は,次のようになります。
- Object[0]
-
EmployeeSetmapクラスのオブジェクト
(EMP_EMPLOYEE_IDカラム,EMP_EMPLOYEE_NAMEカラム,DEP_DEPARTMENT_NAMEカラムの値が各フィールドに格納される)
- Object[1]
-
EMP_MONTHLY_SALARYカラムの値
(3) パラメタの指定方法
ネイティブクエリは,JPQLと同様に,パラメタによって動的に値を設定することができます。WHERE節の中のパラメタを組み込みたい位置に,「?」と数値の組み合わせを記述します。パラメタの値は,QueryインタフェースのsetParameterメソッドで設定します。ただし,ネイティブクエリでは,JPQLの名前付きパラメタは使用できません。
パラメタの記述形式を次に示します。
Query setParameter(int 位置, Object 値)
(4) ネイティブクエリ結果の取得および実行
ネイティブクエリ結果の取得および実行は,JPQLと同様に,Queryインタフェースの次のメソッドを使用します。
-
Object getSingleResult()
-
List getResultList()
-
int executeUpdate()
これらのメソッドの詳細については,「8.16.1 JPQLでのデータベースの参照および更新方法」を参照してください。