ヘッダーをスキップ
Oracle Fusion Middleware Oracle TopLink開発者ガイド
11gリリース1(11.1.1)
B56246-01
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

109基本問合せAPIの使用

この章では、開発サイクル全般で最も一般的に使用される基本的なTopLink問合せAPIのコールについて説明します。

この章の内容は次のとおりです。

詳細は、第111章「詳細問合せAPIの使用」を参照してください。

109.1 セッション問合せの使用

この項では例をあげ、次のセッション問合せメソッドの使用方法を説明します。


注意:

すべてのデータ・ソース操作は作業ユニットを使用して実行することをお薦めします。これがトランザクション、同時実行性および参照制約を管理する最も効率のよい方法です。詳細は、第113章「TopLinkトランザクションの概要」を参照してください。

詳細は、108.6項「セッション問合せ」を参照してください。

109.1.1 セッション問合せを使用したオブジェクトの読取り方法

セッション問合せAPIを使用すると、次の読取り操作を実行できます。

109.1.1.1 セッション問合せを使用したオブジェクトの読取り

readObjectメソッドは、データベースからシングル・オブジェクトを取得します。アプリケーションでは、読取り対象のオブジェクトのクラスを指定する必要があります。基準に一致するオブジェクトがない場合は、null値が返されます。

たとえば、基本的な読取り操作は次のようになります。

session.readObject(MyDomainObject.class);

この例では、MyDomainObjectに使用される表で見つかったMyDomainObjectの最初のインスタンスを返します。TopLinkは、特定のオブジェクト用の問合せパラメータを指定するためのExpressionクラスを提供します。

主キーを使用して特定のシングル・オブジェクトを検索する場合、readAllObjectsメソッドよりもreadObjectメソッドの方が効率的です。これは、readObjectがデータベースにアクセスせずにキャッシュ内でインスタンスを見つけられるためです。readAllObjectsメソッドでは基準に一致するオブジェクトの数がわからないため、一致するオブジェクトがキャッシュ内で見つかったとしても、一致するオブジェクトを見つけるために常にデータベースを検索します。

例109-1 式を使用したreadObject

import oracle.toplink.sessions.*;
import oracle.toplink.expressions.*;

// Use an expression to read in the employee whose last name is Smith. Create an 
// expression using the Expression Builder and use it as the selection criterion // of the search 
Employee employee = (Employee) session.readObject(Employee.class,
                     new ExpressionBuilder().get("lastName").equal("Smith"));

109.1.1.2 セッション問合せを使用したすべてのオブジェクトの読取り

readAllObjectsメソッドは、データベースからオブジェクトのListを取得します。返されるオブジェクトの順序は指定しません。問合せで一致するオブジェクトが見つからない場合は、空のListが返されます。

問合せに対するクラスを指定します。例109-2に示すように、式を含めてさらに複雑な検索基準を定義することもできます。

例109-2 式を使用したreadAllObjects

// Returns a List of employees whose employee salary is greater than 10000
List employees = session.readAllObjects(Employee.class,
                   new ExpressionBuilder.get("salary").greaterThan(10000));

109.1.1.3 セッション問合せを使用したオブジェクトのリフレッシュ

refreshObjectメソッドは、メモリー内のオブジェクトをデータベースのデータで更新します。この操作では、プライベートに所有されたオブジェクトもすべてリフレッシュされます。


注意:

プライベートに所有されたオブジェクトとは、親(ソース・オブジェクト)なしで存在することのできないオブジェクトです。

109.1.2 セッション問合せを使用したオブジェクトの作成、更新および削除方法

セッション問合せAPIを使用すると、次の作成、更新および削除操作を実行できます。

109.1.2.1 セッション問合せを使用したデータベースへのシングル・オブジェクトの書込み

writeObjectメソッドを起動すると、オブジェクトが存在するかどうかを特定するための存在チェックが実行されます。オブジェクトが存在する場合、writeObjectはオブジェクトを更新し、存在しない場合は新規オブジェクトを挿入します。

writeObjectメソッドは、参照整合性が維持されるように、正しい順序で私有されたオブジェクトを書き込みます。

オブジェクトがデータベースに存在するかどうかを確認できない場合は、writeObjectメソッドをコールします。

例109-3 writeObjectを使用したシングル・オブジェクトの書込み

// Create an instance of the employee and write it to the database
Employee susan = new Employee();
susan.setName("Susan");
...
// Initialize the susan object with all other instance variables
session.writeObject(susan);

109.1.2.2 セッション問合せを使用したデータベースへのすべてのオブジェクトの書込み

writeAllObjectsメソッドをコールすると、データベースに複数のオブジェクトを書き込むことができます。writeAllObjectsメソッドは、writeObjectメソッドの場合と同じ存在チェックを実行した後、適切な挿入操作または更新操作を実行します。

例109-4 writeAllObjectsを使用した複数のオブジェクトの書込み

// Read a List of all the current employees in the database.
List employees = session.readAllObjects(Employee.class);

// Modify any employee data as necessary
...

// Create a new employee and add it to the list of employees
Employee susan = new Employee();
...
// Initialize the new instance of employee
employees.add(susan);
// Write all employees to the database. The new instance of susan not currently in 
// the database will be inserted. All the other employees currently stored in the 
// database will be updated
session.writeAllObjects(employees);

109.1.2.3 セッション問合せを使用したデータベースへの新規オブジェクトの追加

insertObjectメソッドはデータベースで新規オブジェクトを作成しますが、挿入操作を試みる前に存在チェックを実行しません。オブジェクトがまだデータベースに存在しないことが確実な場合は、insertObjectメソッドは、writeObjectメソッドより効率的です。オブジェクトが存在する場合にinsertObjectメソッドを実行すると、データベースで例外がスローされます。

109.1.2.4 セッション問合せを使用したデータベースの既存オブジェクトの変更

updateObjectメソッドはデータベース内の既存のオブジェクトを更新しますが、更新操作を試みる前に存在チェックを実行しません。オブジェクトがデータベースに存在することが確実な場合は、writeObjectメソッドよりもupdateObjectの方が効率的です。オブジェクトが存在しない場合にupdateObjectメソッドを実行すると、データベースで例外がスローされます。

109.1.2.5 セッション問合せを使用したデータベースからのオブジェクトの削除

データベースからTopLinkオブジェクトを削除するには、データベースからオブジェクトを読み取り、deleteObjectメソッドをコールします。このメソッドは、指定したオブジェクトとプライベートに所有されたデータの両方を削除します。

109.2 DatabaseQuery問合せの使用

この項では、DatabaseQuery問合せの作成および実行により次のような様々な基本永続化操作を実行する方法について説明します。

109.2.1 DatabaseQueryを使用したオブジェクトの読取り方法

この項では例をあげ、次のようなDatabaseQueryを使用したオブジェクトの読取り方法について説明します。

109.2.1.1 基本DatabaseQuery読取り操作の実行

例109-5は、単純な読取り問合せを示します。この例では、TopLinkの式を使用しますが、問合せ用の独自の引数は使用しません。かわりに、式で提供される検索パラメータを使用します。また、コード内に式を作成しますが、問合せをセッションに登録しません。

例109-5 単純なReadAllQuery

// This example returns a List of employees whose employee ID is > 100

// Initialize the DatabaseQuery by specifying the query type
// and set the reference class for the query
ReadAllQuery query = new ReadAllQuery(Employee.class);

// Retrieve ExpressionBuilder from the query
ExpressionBuilder builder = query.getExpressionBuilder();

// Configure the query execution. Because this example uses an expression,
// it uses the setSelectionCriteria method
query.setSelectionCriteria(builder.get("id").greaterThan(100));

// Execute the query
List employees = (List) session.executeQuery(query);

例109-6は、使用可能な構成オプションをすべて使用した、複雑なreadObject問合せを示します。

例109-6 2つの引数を使用した名前付き読取り問合せ

// Initialize the DatabaseQuery by specifying the query type
// and set the reference class for the query
ReadObjectQuery query = new ReadObjectQuery(Employee.class);
// Retrieve ExpressionBuilder from the query
ExpressionBuilder builder = query.getExpressionBuilder();
// Define two expressions that map to the first and last names of the employee
Expression firstNameExpression = emp.get("firstName").equal(emp.getParameter("firstName"));
Expression lastNameExpression = emp.get("lastName").equal(emp.getParameter("lastName"));

// Configure the query execution. Because this example uses an expression,
// it uses the setSelectionCriteria method
query.setSelectionCriteria(firstNameExpression.and(lastNameExpression));
// Specify the required arguments for the query
query.addArgument("firstName");
query.addArgument("lastName");

// Add the query to the session
session.addQuery("getEmployeeWithName", query);

// Execute the query by referencing its name and providing values
// for the specified arguments
Employee employee =
        (Employee)session.executeQuery("getEmployeeWithName","Bob","Smith");

109.2.1.2 部分オブジェクト問合せを使用したオブジェクトの読取り

例109-7は、部分オブジェクト読取りの使用方法を示します。部分オブジェクト読取りでは、従業員の姓と主キーのみが読み取られます。その結果、データベースから読み取られるデータの量が減少します。

例109-7 部分オブジェクト読取りの使用

/* Read all the employees from the database, ask the user to choose one and return it. 
This uses partial object reading to read just the last name of the employees. 
Since TopLink automatically includes the primary key of the object, the full object 
can easily be read for editing */
List list;
// Fetch data from database and add to list box
ReadAllQuery query = new ReadAllQuery(Employee.class);
query.addPartialAttribute("lastName");
// The next line avoids a query exception
query.dontMaintainCache();
List employees = (List) session.executeQuery(query);
list.addAll(employees);

// Display list box
....
// Get selected employee from list
Employee selectedEmployee = (Employee)session.readObject(list.getSelectedItem());
return selectedEmployee;

109.2.1.3 レポート問合せを使用したオブジェクトの読取り

例109-8は、カナダ人従業員の都市別の合計給与と平均給与を示します。

例109-8 従業員に関するレポート情報の問合せ

ExpressionBuilder emp = new ExpressionBuilder();
ReportQuery query = new ReportQuery(Employee.class, emp);
query.addMaximum("max-salary", emp.get("salary"));
query.addAverage("average-salary", emp.get("salary"));
query.addAttribute("city", emp.get("address").get("city"));

query.setSelectionCriteria(emp.get("address").get("country").equal("Canada"));
query.addOrdering(emp.get("address").get("city"));
query.addGrouping(emp.get("address").get("city"));
List reports = (List) session.executeQuery(query);

ReportQueryクラスには、属性の平均、最大、最小、合計、標準偏差、分散、総数を計算するメソッドなど、広範なレポートAPIがあります。ReportQueryで使用可能なメソッドの詳細は、『Oracle Fusion Middleware Java API Reference for Oracle TopLink』を参照してください。


注意:

ReportQueryReadAllQueryから継承されているため、ほとんどのReadAllQueryプロパティもサポートします。

109.2.1.4 例による問合せを使用したオブジェクトの読取り

例による問合せを使用すると、問合せで使用する属性のみを移入したサンプル・オブジェクト・インスタンスの形式で、問合せ選択基準を指定できます。

例による問合せを定義するには、ReadObjectQueryまたはReadAllQueryを、永続オブジェクトのサンプル・インスタンスおよび例による問合せポリシー(オプション)とともに指定します。サンプル・インスタンスには、問い合せるデータと、オプションでQueryByExamplePolicy「QueryByExamplePolicyの定義」を参照)を含めます。QueryByExamplePolicyには、使用する演算子や無視する属性値など、構成設定を指定します。また、例による問合せと式を組み合せることもできます(「例による問合せと式の結合」を参照)。

詳細は、108.2.8.6項「例による問合せ」を参照してください。

例109-9 例による問合せを使用した従業員の問合せ

例109-9では、従業員Bob Smithを問い合せています。

Employee employee = new Employee();
employee.setFirstName("Bob");
employee.setLastName("Smith");

// Create a query and set Employee as its reference class
ReadObjectQuery query = new ReadObjectQuery(Employee.class);
query.setExampleObject(employee);

Employee result = (Employee) session.executeQuery(query);

例109-10 例による問合せを使用した従業員の住所の問合せ

例109-10では、従業員の住所に対して問合せを行っています。

Employee employee = new Employee();
Address address = new Address();
address.setCity("Ottawa");
employee.setAddress(address);

// Create a query and set Employee as its reference class
ReadAllQuery query = new ReadAllQuery(Employee.class);
query.setExampleObject(employee);

List results = (List) session.executeQuery(query);

QueryByExamplePolicyの定義

TopLinkの例による問合せサポートには、例による問合せポリシーも含まれています。このポリシーを編集すると、例による問合せのデフォルト動作を変更できます。次のような場合のために、ポリシーを変更できます。

  • LIKEなどの演算子を使用して、属性を比較する場合。デフォルトでは、例による問合せで使用できるのはEQUALSのみです。

  • 例による問合せで無視される値のセット(IGNOREセット)を変更する場合。デフォルトで無視される値は、ゼロ(0)、空の文字列およびFALSEです。

  • 属性の値がIGNOREセットに含まれるものであっても、例による問合せでその値を強制的に考慮する場合。

  • 属性値としてisNullまたはnotNullを使用する場合。

例による問合せポリシーを指定するには、問合せにQueryByExamplePolicyのインスタンスを含めます。

例109-11 like演算子を使用した、例による問合せポリシー

例109-11では、文字列に対してlike演算子を使用し、給与がゼロを超えるオブジェクトのみを含めています。

Employee employee = new Employee();
employee.setFirstName("B%");
employee.setLastName("S%");
employee.setSalary(0);

// Create a query and set Employee as its reference class
ReadAllQuery query = new ReadAllQuery(Employee.class);
query.setExampleObject(employee);
// Query by example policy section adds like and greaterThan 
QueryByExamplePolicy policy = new QueryByExamplePolicy();
policy.addSpecialOperation(String.class, "like");
policy.addSpecialOperation(Integer.class, "greaterThan");
policy.alwaysIncludeAttribute(Employee.class, "salary");
query.setQueryByExamplePolicy(policy);
List results = (List) session.executeQuery(query);

例109-12 キーワードを使用した、例による問合せポリシー

例109-12では、文字列に対してキーワードを使用し、値-1を無視します。

Employee employee = new Employee();
employee.setFirstName("bob joe fred");
employee.setLastName("smith mc mac");
employee.setSalary(-1);

// Create a query and set Employee as its reference class
ReadAllQuery query = new ReadAllQuery(Employee.class);
query.setExampleObject(employee);
// Query by example policy section 
QueryByExamplePolicy policy = new QueryByExamplePolicy();
policy.addSpecialOperation(String.class, "containsAnyKeyWords");
policy.excludeValue(-1);
query.setQueryByExamplePolicy(policy);
List results = (List) session.executeQuery(query);

例による問合せと式の結合

例109-13に示すように、さらに複雑な、例による問合せを作成するには、例による問合せをTopLinkの式と結合します。

例109-13 例による問合せと式の結合

Employee employee = new Employee();
employee.setFirstName("Bob");
employee.setLastName("Smith");

// Create a query and set Employee as its reference class
ReadAllQuery query = new ReadAllQuery(Employee.class);

query.setExampleObject(employee);

// Specify expression 
ExpressionBuilder builder = query.getExpressionBuilder();
query.setSelectionCriteria(builder.get("salary").between(100000,200000);
List results = (List) session.executeQuery(query);

109.2.1.5 読取り順序の指定

順序付けは、DatabaseQueryの一般的なオプションです。addOrderingaddAscendingOrderingaddDescendingOrderingのいずれかのメソッドを使用して、ReadAllQueryから返される一連のオブジェクトを順序付けできます。属性名または問合せキーと式に基づいた順序を適用できます。

例109-14 単純な順序付けを行う問合せ

// Retrieves objects ordered by last name then first name in ascending order 
ReadAllQuery query = new ReadAllQuery(Employee.class);
query.addAscendingOrdering ("lastName");
query.addAscendingOrdering ("firstName");
List employees = (List) session.executeQuery(query);

例109-15 複雑な順序付けを行う問合せ

// Retrieves objects ordered by street address, descending
// case-insensitive order of cities, and manager's last name
ReadAllQuery query = new ReadAllQuery(Employee.class);
ExpressionBuilder emp = query.getExpressionBuilder();
query.addOrdering (emp.getAllowingNull("address").get("street"));
query.addOrdering(
    emp.getAllowingNull("address").get("city").toUpperCase().descending());
query.addOrdering(emp.getAllowingNull("manager").get("lastName"));
List employees = (List) session.executeQuery(query);

getAllowingNullを使用し、住所とマネージャのリレーションシップの外部結合を作成していることに注意してください。これにより、住所またはマネージャを持たない従業員もリストに含まれます。

読取り順序の構成の詳細は、119.7.1.4項「すべて読取り問合せの順序の構成」を参照してください。

109.2.1.6 コレクション・クラスの指定

デフォルトでは、ReadAllQueryは結果オブジェクトをListで返します。例109-16に示すように、この問合せを構成して、結果を、CollectionまたはMapインタフェースを実装した任意のコレクション・クラスに入れて返すようにできます。

例109-16 コレクションのコレクション・クラスの指定

ReadAllQuery query = new ReadAllQuery(Employee.class);
query.useCollectionClass(LinkedList.class);
LinkedList employees = (LinkedList) getSession().executeQuery(query);

例109-17 マップのコレクション・クラスの指定

ReadAllQuery query = new ReadAllQuery(Employee.class);
query.useMapClass(HashMap.class, "getFirstName");
HashMap employees = (HashMap) getSession().executeQuery(query);

109.2.1.7 返される最大行の指定

指定した最大行数に問合せを制限できます。この機能を使用して、非常に多くのオブジェクトが返される可能性のある問合せを回避します。

例109-18に示すように、最大行数を指定するには、setMaxRowsメソッドを使用し、問合せの最大行数を表す整数を渡します。

例109-18 返されるオブジェクトの最大サイズの設定

ReadAllQuery query = new ReadAllQuery(Employee.class);
query.setMaxRows(5);
List employees = (List) session.executeQuery(query);

setMaxRowsメソッドでは問合せが返す行数が制限されますが、最初の結果セットの後にその行数を超えるレコードを取得することはできません。

固定の増分で結果セットを参照するには、カーソルまたはカーソル付きストリームを使用します。詳細は、111.11項「カーソルとストリームの問合せ結果の処理」を参照してください。

109.2.1.8問合せレベルにおける問合せタイムアウトの構成

TopLinkで問合せ結果を待つ最大時間を設定できます。これを設定した場合、指定時間が過ぎると、ハングしている問合せや長時間かかっている問合せが強制的に中断されます。タイムアウト時間が経過すると、DatabaseExceptionがスローされます。

例109-19に示すように、問合せごとにタイムアウト時間を指定するには、DatabaseQueryのメソッドsetQueryTimeoutを使用し、タイムアウト時間を、タイムアウト時間が経過するまでの秒数を表す整数として渡します。

例109-19 DatabaseQueryタイムアウト

// Create the appropriate query and set timeout limits
ReadAllQuery query = new ReadAllQuery(Employee.class);
query.setQueryTimeout(2);
try {
    List employees = (List) session.executeQuery(query);
}
catch (DatabaseException ex) {
    // timeout occurs
}

特定のオブジェクト・タイプに対するすべての問合せに関してタイムアウト時間を指定するには、ディスクリプタ・レベルで問合せタイムアウト時間を構成します(119.8項「ディスクリプタ・レベルでの問合せタイムアウトの構成」を参照)。

109.2.1.9 バッチ読取りの使用

バッチ読取りでは、オブジェクトのリレーションシップ属性のマッピングを通じて、問合せの選択基準が伝播されます。バッチ読取り操作を複雑なオブジェクト・グラフにネストさせることもできます。そうすることで、必要なSQLのSELECT文の数が大幅に減少し、データベース・アクセスが効率化されます。

バッチ読取りを実装する際は、次のガイドラインに留意してください。

  • バッチ読取りは、オブジェクトとそのすべての関連オブジェクトを読み取るプロセスに使用します。

  • 双方向リレーションシップの両側でバッチ読取りを有効にしないでください。

  • バッチ読取り操作のネストは、データベースで複数の結合が発生して問合せの実行速度が低下する原因となるため、避けてください。

詳細は、12.12.9.2項「読取り例2: オブジェクトのバッチ読取り」を参照してください。

たとえば、n名の従業員とその関連プロジェクトを読み取る場合、選択操作をn + 1回行う必要があります。従業員はすべて一度に読み取られますが、各従業員のプロジェクトはそれぞれ個別に読み取られます。バッチ読取りを使用すれば、関連プロジェクトも元の選択基準を使用してすべて一度の選択操作で読み取ることができるため、選択操作の回数は合計2回のみとなります。

バッチ読取りを実装してバッチ読取り属性を問合せに追加するには、次の例に示すように、query.addBatchReadAttribute(Expression anExpression) APIを使用します。

…
ReadAllQuery raq = new ReadAllQuery(Trade.class);
ExpressionBuilder tradeBuilder = raq.getBuilder();
…
Expression batchReadProduct = tradeBuilder.get("product");
readAllQuery.addBatchReadAttribute(batchReadProduct);
Expression batchReadPricingDetails = batchReadProduct.get("pricingDetails");
readAllQuery.addBatchReadAttribute(batchReadPricingDetails);
…

ディスクリプタのマッピング・レベルでバッチ読取りを追加することもできます。詳細は、28.5項「バッチ読取りの構成」を参照してください。

バッチ読取りとインダイレクション(遅延ロード)を組み合せると、オブジェクトの属性の読取りを制御できます。たとえば、1対1のバックポインタ・リレーションシップ属性がある場合、問合せの最後に親の所有側オブジェクトがすべてインスタンス化されるまで、バックポインタのインスタンス化を遅らせることができます。これにより、不要なデータベース・アクセスが防止され、TopLinkキャッシュの使用状況が最適化されます。

109.2.1.10ObjectLevelReadQueryを使用した結合読取りの使用

結合読取りをObjectLevelReadQueryとともに使用すると、クラスの問合せを構成して、クラスのインスタンスおよび関連オブジェクトのインスタンスを作成するデータが返されるようにできます。詳細は、108.7.1.5項「結合読取りとオブジェクト・レベルの読取り問合せ」を参照してください。

結合読取りをObjectLevelReadQueryとともに使用するには、Oracle JDeveloper、TopLink Workbench(119.7.1.5項「名前付き問合せの最適化の構成」を参照)、Javaのいずれかを使用できます。


注意:

1対多のマップ属性についての結合式を使用してObjectLevelReadQueryを作成する場合は、TopLink Workbenchは使用できません。この場合はJavaを使用する必要があります。

109.2.1.10.1 Javaの使用

ObjectLevelReadQuery APIを使用して、マッピングに対する結合属性を追加できます。

次のいずれかのAPIを使用できます。

  • ObjectLevelReadQueryのメソッドaddJoinedAttributeは、1対1または1対多のマップ属性の結合式または属性名で使用します。

    このメソッドを使用して、ネストされた結合を含む、複数の結合属性を追加できます。ソースおよびターゲットは、同じクラス・タイプにすることができます。

    1対1のマップ属性についてこのメソッドを使用すると、データベースに1回アクセスすることにより、ObjectLevelReadQueryのクラスおよびそのクラスの1対1にマップされた属性のターゲットを取得できます。

    1対多のマップ属性についてこのメソッドを使用すると、データベースに1回アクセスすることにより、ObjectLevelReadQueryのクラスおよびそのクラスの1対多にマップされた属性のターゲット・コレクションを取得できます。

  • ObjectLevelReadQueryのメソッドsetShouldFilterDuplicatesは、1対多のマップ属性の結合式で使用し、重複する行をフィルタ処理します。このメソッドのデフォルト値はtrueです。

結合式を使用して、ネストされたバッチ読取りおよび内部または外部結合を構成します(110.2.7項「結合リレーションシップと複雑なリレーションシップを表す式」を参照)。マッピングのメソッドuseInnerJoinFetchまたはuseOuterJoinFetchを使用して、内部結合または外部結合を指定することもできます。

例109-20は、TopLink ThreeTierEmployeeサンプル・オブジェクトをベースにしています。この例では、ReadAllQueryが複数属性の結合読取りを行うように構成されています。

例109-20 複数属性の結合読取り

ReadAllQuery query = new ReadAllQuery(Employee.class);

Expression managedEmployees =
          query.getExpressionBuilder().anyOfAllowingNone("managedEmployees");
query.addJoinedAttribute(managedEmployees);
query.addJoinedAttribute(managedEmployees.get("address"));
query.addJoinedAttribute(managedEmployees.anyOf("phoneNumbers"));

List employees = (List) getSession().executeQuery(query);

ObjectLevelReadQueryのメソッドaddJoinedAttribute(java.lang.String attributeName)を使用すると、例109-21に示すように、1つの属性の結合読取りを行うように問合せを構成できます。

例109-21 1つの属性の結合読取り

ReadAllQuery query = new ReadAllQuery(Employee.class);
query.addJoinedAttribute("address");
List employees = (List) getSession().executeQuery(query);

109.2.2 DatabaseQueryを使用したオブジェクトの作成、更新および削除方法

DatabaseSessionを使用すると、DatabaseQueryでオブジェクトを作成、更新または削除できます。詳細は、108.6項「セッション問合せ」を参照してください。

この項の内容は次のとおりです。

109.2.2.1 書込み問合せの使用

書込み問合せを実行するには、セッションのwriteObjectメソッドを使用するかわりに、WriteObjectQueryインスタンスを使用します。同様に、DeleteObjectQueryUpdateObjectQueryInsertObjectQueryの各オブジェクトをそれぞれのSessionメソッドのかわりに使用します。

例109-22 WriteObjectQueryの使用

WriteObjectQuery writeQuery = new WriteObjectQuery();
writeQuery.setObject(domainObject);
session.executeQuery(writeQuery);

例109-23 InsertObjectQuery、UpdateObjectQueryおよびDeleteObjectQueryの使用

InsertObjectQuery insertQuery= new InsertObjectQuery();
insertQuery.setObject(domainObject);
session.executeQuery(insertQuery);

// When you use UpdateObjectQuery without a unit of work,
// UpdateObjectQuery writes all direct attributes to the database
UpdateObjectQuery updateQuery= new UpdateObjectQuery();
updateQuery.setObject(domainObject2);
session.executeQuery(updateQuery);

DeleteObjectQuery deleteQuery = new DeleteObjectQuery();
deleteQuery.setObject(domainObject2);
session.executeQuery(deleteQuery);

109.2.2.2 非カスケード書込み問合せの実行

書込み問合せを実行すると、デフォルトではオブジェクトとその私有された部分の両方がデータベースに書き込まれます。私有された部分を更新しない書込み問合せを作成するには、問合せの定義にdontCascadePartsメソッドを含めます。

このメソッドは、次の目的で使用します。

  • オブジェクトのダイレクト属性のみが変更されたことがわかっている場合に、パフォーマンスを向上させること。

  • 独立した新規オブジェクトの大きなグループを作成する場合に、参照整合性の依存関係を解決すること。


    注意:

    作業ユニットでは参照整合性が内部的に解決されるため、作業ユニットを使用してデータベースに書き込む場合はこのメソッドは不要です。

例109-24 非カスケード書込み問合せの実行

// the Employee is an existing employee read from the database
Employee.setFirstName("Bob");
UpdateObjectQuery query = new UpdateObjectQuery();
query.setObject(Employee);
query.dontCascadeParts();
session.executeQuery(query);

109.2.2.3 書込み問合せ中のアイデンティティ・マップ・キャッシュの無効化

データベースにオブジェクトを書き込む場合、TopLinkでは、デフォルトでセッション・キャッシュにオブジェクトがコピーされます。問合せにおけるこの動作を無効にするには、問合せでdontMaintainCacheメソッドをコールします。そうすることで、データベースにオブジェクトを挿入する際の問合せのパフォーマンスが向上しますが、この方法は後でアプリケーションで必要にならないオブジェクトに対してのみ使用できます。

例109-25 書込み問合せ中のアイデンティティ・マップ・キャッシュの無効化

例109-25は、フラット・ファイルからすべてのオブジェクトを読み取り、オブジェクトの新規コピーを表に書き込みます。

// Reads objects from an employee file and writes them to the employee table
void createEmployeeTable(String filename, Session session) {
   Iterator iterator;
   Employee employee;
   // Read the employee data file
   List employees = Employee.parseFromFile(filename);
   Iterator iterator = employees.iterator();
   while (iterator.hasNext()) {
      Employee employee = (Employee) iterator.next();
      InsertObjectQuery query = new InsertObjectQuery();
      query.setObject(employee);
      query.dontMaintainCache();
      session.executeQuery(query);
   }
}

注意:

アイデンティティ・マップを無効にするのは、後続の操作においてオブジェクト・アイデンティティが重要ではない場合にかぎってください。

109.2.3 DatabaseQueryを使用した複数のオブジェクトの更新および削除方法

作業ユニットを使用すると、複数のオブジェクトに対して更新および削除操作を実行できます。

この項の内容は次のとおりです。

109.2.3.1 UpdateAllQueryの使用

UpdateAllQueryを使用すると、一度に多数のオブジェクトを更新できます。この問合せを使用すると、オブジェクトをメモリーに読み取って個別に更新するかわりに、1つのSQL文で多数のオブジェクトを更新できます。例109-26では、すべての常勤従業員を昇給させるUpdateAllQueryを示しています。

例109-26 UpdateAllQueryの使用

// Give all full time employees a 10% raise
UpdateAllQuery updateQuery = new UpdateAllQuery(Employee.class);
ExpressionBuilder employee = updateQuery.getExpressionBuilder();
updateQuery.setSelectionCriteria(employee.get("status").equal("FULL_TIME"));
updateQuery.addUpdateExpression(employee.get("salary"),
    ExpressionMath.multiply(employee.get("salary"), new Float(1.10)));

UpdateAllQueryでは、キャッシュが使用され、キャッシュは常に最新の状態に維持されます。UpdateAllQueryを構成してキャッシュを無効にする(102.2.5項「キャッシュの無効化」を参照)には、キャッシュの使用状態をINVALIDATE_CACHE(デフォルト)に設定するか、NO_CACHEオプションを指定してキャッシュの使用を停止します。これらの設定は、setCacheUsageメソッドを通じて操作できます。一致する式のキャッシュのみを更新できます。キャッシュの詳細は、第102章「キャッシュの概要」を参照してください。


注意:

属性は集約内にのみ設定できます。集約全体に対しては設定できません。

UpdateAllQueryをオプティミスティック・ロック(16.4項「ディスクリプタとロック」を参照)と組み合せ、データベースの行を更新するレベルで使用できます。この場合、キャッシュの更新は行われません。データベースのロック・フィールドが更新されます。また、バージョンおよびタイムスタンプ・ロックのサポートに加え、フィールド・ロックの間接的サポートも提供されます。

109.2.3.2 DeleteAll問合せの使用

例109-27は、すべてのパートタイム従業員の地位を削除するDeleteAllQueryを示します。

例109-27 DeleteAllQueryの使用

// Delete all part-time employeesDeleteAllQuery deleteQuery = new DeleteAllQuery(Employee.class);
ExpressionBuilder employee = deleteQuery.getExpressionBuilder();
deleteQuery.setSelectionCriteria(employee.get("status").equal("PART_TIME"));
deleteQuery.setObjects(domainObjects);
session.executeQuery(deleteQuery);

詳細は、108.7.3.6項「DeleteAllQuery」を参照してください。

109.2.4 DatabaseQueryを使用したデータの読取り方法

この項の内容は次のとおりです。

109.2.4.1 DataReadQueryの使用

例109-28に示すように、DataReadQueryを使用すると、結果セットを表すRecordオブジェクトのCollectionを返す選択SQL文字列を実行できます。

例109-28 DataReadQueryの使用

DataReadQuery dataReadQuery = new DataReadQuery();
dataReadQuery.setSQLString("Select * from EMPLOYEE");

// queryResults is a list of Record objects
List queryResults = (List)session.executeQuery(dataReadQuery);

109.2.4.2 DirectReadQueryの使用

例109-29に示すように、DirectReadQueryを使用すると、データの1列(1つのフィールド)を読み取り、結果セットを表すRecordオブジェクトのCollectionを返すことができます。

例109-29 DirectReadQueryの使用

DirectReadQuery directReadQuery = new DirectReadQuery();
directReadQuery.setSQLString("Select * from EMPLOYEE");

// queryResults is a list of Record objects
List queryResults = (List)session.executeQuery(directReadQuery);

109.2.4.3 ValueReadQueryの使用

ValueReadQueryを使用すると、単一データ値(1つのフィールド)を読み取ることができます。例109-30に示すように、単一データ値が返されます。または、行が返されない場合は、NULLが返されます。

例109-30 ValueReadQueryの使用

ValueReadQuery valueReadQuery = new ValueReadQuery();
valueReadQuery.setSQLString("SELECT DISTINCT CURRENT TIMESTAMP FROM SYSTABLES");

// result is a single Object value
Object result = session.executeQuery(valueReadQuery);

警告:

検証されていないSQL文字列をメソッド(たとえばsetSQLStringメソッド)に渡せるようにすると、SQLインジェクション攻撃に対してアプリケーションが脆弱になります。


109.2.5 DatabaseQueryを使用したデータの更新方法

例109-31に示すように、DataModifyQueryを使用すると、選択を行わないSQL文を(直接またはSQLCallとして)実行できます。これは、SessionメソッドexecuteNonSelectingCallと同等です(109.4項「SQLCallの使用」を参照)。

例109-31 DataModifyQueryの使用

DataModifyQuery query = new DataModifyQuery(new SQLCall("Delete from Employee"));
session.executeQuery(query);

109.2.6 DatabaseQueryにおけるカスタムSQL文字列の指定方法

すべてのDatabaseQueryオブジェクトには、カスタムSQL文字列を定義できるsetSQLStringメソッドが用意されています。

問合せにおけるカスタムSQLの使用方法の詳細は、109.4項「SQLCallの使用」を参照してください。

例109-32では、SQLを使用してすべての従業員IDを読み取っています。

例109-32 SQLを使用したダイレクト読取り問合せ

DirectReadQuery query = new DirectReadQuery();
query.setSQLString("SELECT EMP_ID FROM EMPLOYEE");
List ids = (List) session.executeQuery(query);

例109-33では、SQLを使用して別のデータベースに切り替えています。

例109-33 SQLを使用したデータ変更問合せ

DataModifyQuery query = new DataModifyQuery();
query.setSQLString("USE SALESDATABASE");
session.executeQuery(query);

警告:

検証されていないSQL文字列をメソッド(たとえばsetSQLStringメソッド)に渡せるようにすると、SQLインジェクション攻撃に対してアプリケーションが脆弱になります。


109.2.7 DatabaseQueryにおけるカスタムJPQL文字列の指定方法

詳細は、『EclipseLink Developer's Guide』の「How to Specify a Custom JPQL String in a DatabaseQuery」(http://wiki.eclipse.org/Using_Basic_Query_API_%28ELUG%29#How_to_Specify_a_Custom_JPQL_String_in_a_DatabaseQuery)を参照してください。

109.2.8 DatabaseQueryにおけるカスタムEJB QL文字列の指定方法

すべてのDatabaseQueryオブジェクトには、カスタムEJB QL文字列を指定できるsetEJBQLStringメソッドが用意されています。

JPA問合せの詳細は、109.2.7項「DatabaseQueryにおけるカスタムJPQL文字列の指定方法」を参照してください。

参照クラスおよびSELECT句の両方を指定し、問合せを通常どおり実行します。

例109-34 EJB QL

ReadAllQuery query = new ReadAllQuery(EmployeeBean.class);
query.setEJBQLString("SELECT OBJECT(emp) FROM EmployeeBean emp");
…
List returnedObjects = (List)session.executeQuery(query);

例109-35例109-34と同様の問合せを定義したものですが、引数のVectorを作成して入力し、executeQueryメソッドに渡しています。

例109-35 EJB QLを使用し、引数を渡す単純なReadAllQuery

// First define the query
ReadAllQuery query = new ReadAllQuery(EmployeeBean.class);
query.setEJBQLString("SELECT OBJECT(emp) FROM EmployeeBean emp WHERE emp.firstName = ?1");
query.addArgument("1", String.class);
...
// Next define the arguments
Vector arguments = new Vector();
arguments.add("Bob");
...
// Finally, execute the query passing in the arguments
List returnedObjects = (List)session.executeQuery(query, arguments);

109.2.9 DatabaseQueryにおけるパラメータ使用のSQLおよびSQL文のキャッシュの使用方法

デフォルトでは、TopLinkでパラメータ使用のSQL(パラメータ・バインド)およびSQL文のキャッシュを有効にします。そうすることで、TopLinkではプリコンパイルされたSQL文を使用し、すべてのSQLパラメータをバインドして、プリコンパイルされたSQL文をキャッシュします。この問合せを再実行するときにはSQLのプリコンパイルが不要になるため、パフォーマンスが向上します。

個々の問合せでパラメータ使用のSQLおよびSQL文のキャッシュを無効にするには、DatabaseQueryのメソッドsetShouldBindAllParametersおよびsetShouldcacheStatementを使用し、falseの引数付きで渡します。この機能を再度有効にするには、trueの引数付きで渡します。

例109-36 パラメータ使用のSQLによる単純なReadObjectQuery

ReadObjectQuery query = new ReadObjectQuery(Employee.class);
query.setShouldBindAllParameters(true);
query.setShouldCacheStatement(true);

あるいは、次のいずれかのレベルでパラメータ使用のSQLとバインドを構成できます。

データ・アクセスの最適化のためのパラメータ使用のSQLおよびバインドの使用方法の詳細は、12.11.5項「パラメータ使用のSQL(パラメータ・バインド)とプリコンパイルされたSQL文のキャッシュを使用した最適化方法」を参照してください。


注意:

Java EEデータ・ソースまたは外部接続プールを使用するアプリケーションでは、TopLinkにおいてではなくJava EEサーバーのデータ・ソースにおいて、文のキャッシュを構成する必要があります。

109.3 名前付き問合せの使用

名前付き問合せは、一度作成すると、基礎となる関連オブジェクトすべてとともに後で効率的に再利用できるため、頻繁に実行される操作に適しており、アプリケーションのパフォーマンスを向上させることができます。

名前付き問合せはセッション・レベル(89.13項「セッション・レベルでの名前付き問合せの構成」を参照)またはディスクリプタ・レベル(119.7項「ディスクリプタ・レベルでの名前付き問合せの構成」を参照)で構成できます。

セッション・レベルでの名前付き問合せの場合は、次のセッションAPIメソッドのいずれかを使用して問合せを実行できます。

例109-37 セッション・レベルでの名前付き問合せの実行

Vector args = new Vector();
args.add("Sarah");
Employee sarah = (Employee)session.executeQuery(
    "employeeReadByFirstName",
    args
);

ディスクリプタ・レベルでの名前付き問合せの場合は、例109-38に示すように、次のセッションAPIコールのいずれかを使用して問合せを実行できます。

例109-38 ディスクリプタ・レベルでの名前付き問合せの実行

Vector args = new Vector();
args.add("Sarah");
Employee sarah = (Employee)session.executeQuery(
    "ReadByFirstName",
    Employee.class,
    args
);

詳細は、108.8項「名前付き問合せ」を参照してください。

109.4 SQLCallの使用

TopLinkの式フレームワークを使用すると、複雑な問合せをオブジェクト・レベルで定義できます。アプリケーションでより複雑な問合せ、またはデータに直接アクセスする問合せを必要とする場合は、カスタムSQL文字列をSQLCallオブジェクトに指定し、DatabaseQueryのコンテキストまたはCallオブジェクト実行用のセッションAPIを使用して、SQL文字列を実行できます。

どのような問合せにも式のかわりにSQLCallオブジェクトを指定できますが、SQLCallに含まれるSQL文字列は、問い合せたクラスのインスタンスの作成に必要なデータをすべて返す必要があります。

SQL文字列には、JDBCデータ・タイプを使用する入力、出力、および入出力引数を含む複雑なSQL問合せを指定できます。


警告:

検証されていないSQL文字列をメソッドに渡せるようにすると、SQLインジェクション攻撃に対してアプリケーションが脆弱になります。


109.4.1 引数なしのSQLCallの構成方法

SQLCallは引数なしでも構成でき、セッションAPIを使用して直接実行できます。この手法は、引数なしで(またはハードコードされた引数の値を指定して)SQL文字列を実行する場合に使用します。

引数なしのSQLCall入力の構成手順:

  1. SQLCallオブジェクトをインスタンス化します。

  2. コンストラクタにSQL文字列を渡します(例109-39を参照)。

    または、SQLCallメソッドのsetSQLStringを使用することもできます。

  3. 適切なセッションAPIを使用してSQLCallを実行します(例109-39を参照)。

    定義するSQL文字列のタイプに応じて、次のSessionメソッドのいずれかを使用できます。

    • executeSelectingCall: それぞれがデータベース行を表しているRecordオブジェクトからなるListを返します。

    • executeNonSelectingCall: voidを返します。

    例109-39 引数なしのSQLCallの実行

    List result = session.executeSelectingCall(
        new SQLCall("SELECT * FROM EMPLOYEE WHERE DEPT_ID = 44")
    );
    

109.4.2 JDBCデータ・タイプを使用した引数を持つSQLCallの構成方法

入力、出力、入出力引数のいずれかの組合せをとるSQLCallを構成できます。この手法は、実行時に引数の値をSQLCallにバインドするか、実行時間にSQLCallからの出力値を受け取るか、あるいはその両方を実行する場合に使用します。

JDBCデータ・タイプを使用した引数を持つSQLCallの構成手順:

  1. SQLCallオブジェクトをインスタンス化します。

  2. SQL文字列を作成し、入力、出力または入出力のいずれかとして引数を指定します。

    TopLinkでは、次のようにSQLCallのカスタムSQL文字列のトークンの先頭に1つ以上のシャープ記号(#)が付いている場合は、そのトークンが引数であるものとみなします。

    • 入力パラメータ接頭辞: #例109-40を参照)

    • 出力パラメータ接頭辞: ##例109-41を参照)

    • 入出力パラメータ接頭辞: ###例109-42を参照)

  3. コンストラクタにSQL文字列を渡します(例109-40例109-41および例109-42を参照)。

    または、SQLCallメソッドのsetSQLStringを使用することもできます。

  4. 各出力引数について、適切なSQLCallメソッドsetCustomSQLArgumentTypeを使用してTopLinkで使用するJavaデータ・タイプを指定し、出力値を返します(例109-41を参照)。

    入力引数の場合、TopLinkではJavaデータ・タイプが自動的に適切なJDBCデータ・タイプに変換されます。

    入出力引数の場合、入力値のタイプによって、出力値のタイプが決まります。例109-42が示すように、in_outに渡される引数の値のデータ・タイプはString(MacDonald)であり、このためTopLinkでは、Stringとして(EMP_IDの)出力値を返します。

  5. SQL文字列用に適切なDatabaseQueryをインスタンス化します。

  6. DatabaseQueryメソッドsetCallを使用し、SQLCallDatabaseQueryを構成します(例109-40例109-41および例109-42を参照)。

  7. DatabaseQueryメソッドaddArgumentを使用し、すべての入力引数および入出力引数の名前を指定します(例109-40例109-41および例109-42を参照)。

  8. 手順7で引数名を指定したときと同じ順序で引数の値のVectorを作成します(例109-40例109-41および例109-42を参照)。

  9. 引数に値をバインドし、SessionメソッドexecuteQuery(DatabaseQuery, java.util.Vector)を使用して引数の値のDatabaseQueryおよびVectorに渡し、DatabaseQueryを実行します(例109-40例109-41および例109-42を参照)。

    例109-40 入力引数(JDBCデータ・タイプ接頭辞#付き)を持つSQLCallの指定

    SQLCall sqlCall = new SQLCall("INSERT INTO EMPLOYEE (L_NAME) VALUES (#last_name)");
    
    DataModifyQuery query = new DataModifyQuery();
    query.setCall(sqlCall);
    query.addArgument("last_name");   // input
    
    Vector arguments = new Vector();
    arguments.add("MacDonald");
    session.executeQuery(query, arguments);
    

    例109-41 出力引数(JDBCデータ・タイプ接頭辞###付き)を持つSQLCallの指定

    SQLCall sqlCall = new SQLCall(
        "BEGIN INSERT INTO EMPLOYEE (L_NAME) VALUES (#last_name)
        RETURNING EMP_ID INTO ###employee_id; END;");
    
    sqlCall.setCustomSQLArgumentType("employee_id", Integer.class); // specify output value type
    
    ValueReadQuery query = new ValueReadQuery();
    query.setCall(sqlCall);
    query.addArgument("last_name");   // input
    
    Vector args = new Vector();
    args.add("MacDonald");
    
    Integer employeeID = (Integer) getSession().executeQuery(query, args);
    

    例109-42 入出力引数(JDBCデータ・タイプ接頭辞####付き)を持つSQLCallの指定

    SQLCall sqlCall = new SQLCall(
        "BEGIN INSERT INTO EMPLOYEE (L_NAME) VALUES (####in_out)
        RETURNING EMP_ID INTO ####in_out; END;");
    
    ValueReadQuery query = new ValueReadQuery();
    query.setCall(sqlCall);
    query.addArgument("in_out");   // input and outpu
    
    Vector args = new Vector();
    args.add("MacDonald");         // type of input argument determines type of output value
    
    String lastName = (String) getSession().executeQuery(query, args);
    

109.4.3 SQLCallの使用について

SQLコールを使用する際に、ReturningPolicyを使用して、TopLinkでパラメータに書き込むかまたはデータベースによって生成された値を取得するかを制御できます。

ストアド・プロシージャまたはストアド・ファンクションを起動する場合は、StoredProcedureCallまたはStoredFunctionCallを使用します。

あるいは、DatabaseQueryに直接単純なSQL文字列を指定することもできます。この方法を使用すると、SQL文字列が単純な場合、ハードコードされた引数を使用して(または引数なし)SQLCallオブジェクト作成のオーバーヘッドを回避でき、SQLCallが提供する追加のAPIが不要です。

詳細は、次を参照してください。

109.5 StoredProcedureCallの使用

TopLinkの式フレームワークを使用すると、複雑な問合せをオブジェクト・レベルで定義できます。アプリケーションでより複雑な問合せ、またはデータベースに付属の既存のストアド・プロシージャを起動する問合せを必要とする場合は、JDBCおよびPL/SQLの両方のデータ・タイプを使用してStoredProcedureCallオブジェクトを定義し、DatabaseQueryのコンテキストでストアド・プロシージャを起動できます。

Oracleデータベースを使用している場合は、JDBCおよびPL/SQL(非JDBC)の両方のデータ・タイプに渡すことができます。

Oracle以外のデータベースを使用している場合は、JDBCデータ・タイプにのみ渡すことができます。

この項の内容は次のとおりです。

109.5.1 引数なしのStoredProcedureCallの構成方法

StoredProcedureCallは引数なしでも構成でき、セッションAPIを使用して直接実行できます。この手法は、引数をとらないあるいは値を返さないストアド・プロシージャを実行する場合に使用します。

JDBCデータ・タイプを使用した引数なしのStoredProcedureCallの構成手順:

  1. StoredProcedureCallオブジェクトをインスタンス化します。

  2. 例109-43に示すように、StoredProcedureCallメソッドsetProcedureNameを使用して、実行するストアド・プロシージャの名前を設定します。

  3. 適切なセッションAPIを使用してStoredProcedureCallを実行します(例109-43を参照)。

    実行するストアド・プロシージャのタイプに応じて、次のSessionメソッドのいずれかを使用できます。

    • executeSelectingCall: それぞれがデータベース行を表しているRecordオブジェクトからなるListを返します。

    • executeNonSelectingCall: voidを返します。

    例109-43 引数なしのStoredProcedureCallの実行

    StoredProcedureCall spcall = new StoredProcedureCall();
    spcall.setProcedureName("Read_All_Employees");
    spcall.useNamedCursorOutputAsResultSet("RESULT_SET");
    
    List employees = (List) getSession().executeSelectingCall(spcall);
    

109.5.2 JDBCデータ・タイプを使用した引数を持つStoredProcedureCallの構成方法

入力、出力、入出力引数のいずれかの組合せをとるStoredProcedureCallを構成できます。この手法は、実行時に引数の値をStoredProcedureCallにバインドするか、実行時間にStoredProcedureCallからの出力値を受け取るか、あるいはその両方を実行する場合に使用します。


注意:

このプロシージャは、入力、出力および入出力引数がすべてJDBCデータ・タイプである場合に使用します。1つまたは複数の引数がPL/SQL(非JDBC)データ・タイプである場合は、109.5.3項「PL/SQLデータ・タイプ引数を持つPLSQLStoredProcedureCallの構成方法」を参照してください。

JDBCデータ・タイプを使用した引数を持つStoredProcedureCallの構成手順:

  1. StoredProcedureCallオブジェクトをインスタンス化します。

  2. StoredProcedureCallメソッドsetProcedureNameを使用し、コールするストアド・プロシージャの名前を指定します(例109-44例109-45および例109-46を参照)。

  3. 各引数について、適切なStoredProcedureCallメソッドを使用して引数が入力、出力または入出力のいずれかの引数であるかを指定します。

    • 入力引数の場合: addNamedArgument例109-44を参照)

    • 出力引数の場合: addNamedOutputArgument例109-45を参照)

    • 入出力引数の場合: addNamedInOutputArgument例109-46を参照)

    通常は、すべての出力引数および入出力引数に対して戻りJavaデータ・タイプを常に指定します(例109-45および例109-46を参照)。戻りJavaデータ・タイプを指定しない場合、デフォルトはjava.lang.Stringです。

    一般的に引数を指定するには、ストアド・プロシージャ引数名をそのまま使用します。ただし、ストアド・プロシージャ引数名を、DatabaseQueryで使用する代替名に関連付けることができます(例109-44を参照)。ストアド・プロシージャ引数名が曖昧な場合は、この方法を使用して有効な引数名を指定します。

  4. ストアド・プロシージャ用に適切なDatabaseQueryをインスタンス化します。

  5. DatabaseQueryメソッドsetCallを使用し、StoredProcedureCallDatabaseQueryを構成します(例109-44例109-45および例109-46を参照)。

  6. DatabaseQueryメソッドaddArgumentを使用し、すべての入力引数および入出力引数の名前を指定します(例109-44例109-45および例109-46を参照)。

    手順3でストアド・プロシージャ引数名を有効な代替名に関連付けた場合は、DatabaseQueryメソッドaddArgumentでその代替名を使用します(例109-44を参照)。

  7. 手順6で引数名を指定したときと同じ順序で引数の値のVectorを作成します(例109-44例109-45および例109-46を参照)。

  8. 引数に値をバインドし、SessionメソッドexecuteQuery(DatabaseQuery, java.util.Vector)を使用して引数の値のDatabaseQueryおよびVectorに渡し、DatabaseQueryを実行します(例109-44例109-45および例109-46を参照)。

    例109-44 入力引数(JDBCデータ・タイプ)を持つStoredProcedureCallの指定

    // CREATE PROCEDURE INSERT_EMPLOYEE(L_NAME IN VARCHAR) AS
    // BEGIN
    //     Insert an EMP record initialized with last name.
    // END;
    
    StoredProcedureCall spcall = new StoredProcedureCall();
    spcall.setProcedureName("INSERT_EMPLOYEE");
    spcall.addNamedArgument("L_NAME", "last_name");
    
    DataModifyQuery query = new DataModifyQuery();
    query.setCall(spcall);
    query.addArgument("last_name");   // input
    
    Vector arguments = new Vector();
    arguments.add("MacDonald");
    session.executeQuery(query, arguments);
    

    例109-45 出力引数(JDBCデータ・タイプ)を持つStoredProcedureCallの指定

    // CREATE PROCEDURE GET_EMP_ID(L_NAME IN VARCHAR, EMP_ID OUT INTEGER) AS
    // BEGIN
    //     Insert an EMP record initialized with last name and return the EMP_ID for this record.
    // END;
    
    StoredProcedureCall spcall = new StoredProcedureCall();
    spcall.setProcedureName("GET_EMP_ID");
    spcall.addNamedArgument("L_NAME");
    spcall.addNamedOutputArgument(
        "EMP_ID",      // procedure parameter name
        "EMP_ID",      // out argument field name
        Integer.class  // Java type corresponding to type returned by procedure
    );
    
    ValueReadQuery query = new ValueReadQuery();
    query.setCall(spcall);
    query.addArgument("L_NAME");   // input
    
    Vector args = new Vector();
    args.add("MacDonald");
    
    Integer employeeID = (Integer) getSession().executeQuery(query, args);
    

    例109-46 入出力引数(JDBCデータ・タイプ)を持つStoredProcedureCallの指定

    // CREATE PROCEDURE INSERT_EMPLOYEE(IN_OUT INOUT VARCHAR) AS
    // BEGIN
    //     Insert an EMP record initialized with last name
    //     and return the EMP_CODE_NAME for this record.
    // END;
    
    StoredProcedureCall spcall = new StoredProcedureCall();
    spcall.setProcedureName("INSERT_EMP"); // returns EMP_CODE_NAME after insert
    spcall.addNamedInOutputArgument(
        "IN_OUT",       // procedure parameter name
        "IN_OUT",       // out argument field name
        String.class    // Java type corresponding to type returned by procedure
    );
    
    ValueReadQuery query = new ValueReadQuery();
    query.setCall(sqlCall);
    query.addArgument("INOUT");   // input and outpu
    
    Vector args = new Vector();
    args.add("MacDonald");         // type of input argument determines type of output value
    
    String employeeCode = (String) getSession().executeQuery(query, args));
    

109.5.3 PL/SQLデータ・タイプ引数を持つPLSQLStoredProcedureCallの構成方法

入力引数、出力引数、入出力引数のいずれかの組合せのデータ・タイプがPL/SQL(非JDBC)の場合には、oracle.toplink.platform.database.oracle.PLSQLStoredProcedureCallクラスを使用する必要があります。この手法は、実行時に引数の値をPLSQLStoredProcedureCallにバインドするか、実行時間にPLSQLStoredProcedureCallからの出力値を受け取るか、あるいはその両方を実行する場合に使用します。


注意:

すべての引数がJDBC(非PL/SQLデータ・タイプ)である場合は、109.5.2項「JDBCデータ・タイプを使用した引数を持つStoredProcedureCallの構成方法」を参照してください。

JDBCデータ・タイプおよびPL/SQLデータ・タイプを使用した引数を持つPLSQLStoredProcedureCallの構成手順:

  1. PLSQLStoredProcedureCallオブジェクトをインスタンス化します。

  2. PLSQLStoredProcedureCallメソッドsetProcedureNameを使用し、コールするストアド・プロシージャの名前を指定します(例109-47例109-48および例109-49を参照)。

  3. 各引数について、適切なPLSQLStoredProcedureCallメソッドを使用して、引数が入力、出力または入出力引数のいずれであるかを指定します。

    • 入力引数の場合: addNamedArgument例109-47を参照)

    • 出力引数の場合: addNamedOutputArgument例109-48を参照)

    • 入出力引数の場合: addNamedInOutputArgument例109-49を参照)

    入力、出力および入出力のすべての引数にデータ・タイプを指定する必要があります。JDBCタイプの指定にはoracle.toplink.platform.database.jdbc.JDBCTypesを、PL/SQL(非JDBC)タイプの指定にはoracle.toplink.platform.database.oracle.OraclePLSQLTypesを使用します。

    JDBCおよびPL/SQL入力引数(および入出力引数のinの値)の場合は、十分なサイズと精度のあるJavaタイプを引数に使用できます。

    JDBC出力引数(および入出力引数のoutの値)の場合、TopLinkでは従来どおり、JDBCデータ・タイプをJavaタイプに変換します。PL/SQL出力引数(および入出力引数のoutの値)の場合、TopLinkではPL/SQLデータ・タイプを、表109-1に示すJavaデータ・タイプに変換します。

    一般的に引数を指定するには、ストアド・プロシージャ引数名をそのまま使用します。ただし、ストアド・プロシージャ引数名を、DatabaseQueryで使用する代替名に関連付けることができます(例109-47を参照)。ストアド・プロシージャ引数名が曖昧な場合は、この方法を使用して有効な引数名を指定します。

  4. ストアド・プロシージャ用に適切なDatabaseQueryをインスタンス化します。

  5. DatabaseQueryメソッドsetCallを使用し、PLSQLStoredProcedureCallDatabaseQueryを構成します(例109-47例109-48および例109-49を参照)。

  6. DatabaseQueryメソッドaddArgumentを使用し、すべての入力引数および入出力引数の名前を指定します(例109-47例109-48および例109-49を参照)。

    手順3でストアド・プロシージャ引数名を有効な代替名に関連付けた場合は、DatabaseQueryメソッドaddArgumentでその代替名を使用します(例109-47を参照)。

  7. 手順6で引数名を指定したときと同じ順序で引数の値のVectorを作成します(例109-47例109-48および例109-49を参照)。

  8. 引数に値をバインドし、SessionメソッドexecuteQuery(DatabaseQuery, java.util.Vector)を使用して引数の値のDatabaseQueryおよびVectorに渡し、DatabaseQueryを実行します(例109-47例109-48および例109-49を参照)。

    例109-47 入力引数(JDBCおよびPL/SQLデータ・タイプ)を持つPLSQLStoredProcedureCallの指定

    // CREATE PROCEDURE INSERT_EMPLOYEE(L_NAME IN VARCHAR, MANAGER IN BOOLEAN) AS
    // BEGIN
    //     Insert an EMP record initialized with last name and whether or not the employee
    //     is a manager.
    // END;
    
    PLSQLStoredProcedureCall plsqlcall = new PLSQLStoredProcedureCall();
    plsqlcall.setProcedureName("INSERT_EMPLOYEE");
    plsqlcall.addNamedArgument("L_NAME", JDBCTypes.VARCHAR_TYPE, 40);  // must define length
    plsqlcall.addNamedArgument("MANAGER", OraclePLSQLTypes.PLSQLBoolean);
    
    DataModifyQuery query = new DataModifyQuery();
    query.setCall(plsqlcall);
    query.addArgument("L_NAME");    // input
    query.addArgument("MANAGER");      // input
    
    Vector arguments = new Vector();
    arguments.add("MacDonald");
    arguments.add(Integer.valueOf(1));
    session.executeQuery(query, arguments);
    

    例109-48 出力引数(JDBCおよびPL/SQLデータ・タイプ)を持つPLSQLStoredProcedureCallの指定

    // CREATE PROCEDURE GET_EMP_ID(L_NAME IN VARCHAR, EMP_ID OUT PLS_INTEGER) AS
    // BEGIN
    //     Insert an EMP record initialized with last name and return EMP_ID for this row.
    // END;
    
    PLSQLStoredProcedureCall plsqlcall = new PLSQLStoredProcedureCall();
    plsqlcall.setProcedureName("GET_EMP_ID");
    plsqlcall.addNamedArgument("L_NAME", JDBCTypes.VARCHAR_TYPE, 25); // must define length
    plsqlcall.addNamedOutputArgument("EMP_ID", OraclePLSQLTypes.PLSQLInteger);
    
    ValueReadQuery query = new ValueReadQuery();
    query.setCall(plsqlcall);
    query.addArgument("L_NAME");   // input
    
    Vector args = new Vector();
    args.add("MacDonald");
    
    Number employeeID = (Number) getSession().executeQuery(query, args);
    

    例109-49 入出力引数(JDBCおよびPL/SQLデータ・タイプ)を持つPLSQLStoredProcedureCallの指定

    // CREATE PROCEDURE INSERT_EMP(IN_OUT INOUT PLS_INTEGER) AS
    // BEGIN
    //     Insert an EMP record initialized with department id and return
    //     the EMP_ID for this record.
    // END;
    
    PLSQLStoredProcedureCall plsqlcall = new PLSQLStoredProcedureCall();
    plsqlcall.setProcedureName("INSERT_EMP");
    plsqlcall.addNamedInOutputArgument("IN_OUT", OraclePLSQLTypes.PLSQLInteger);
    
    ValueReadQuery query = new ValueReadQuery();
    query.setCall(plsqlcall);
    query.addArgument("IN_OUT");       // input and outpu
    
    Vector args = new Vector();
    args.add(Integer.valueOf(1234));   // department id
    
    Integer employeeID = new Integer(BigDecimal.intValue(
                                     getSession().executeQuery(query, args)));
    

109.5.4 JDBCデータ・タイプを使用したStoredProcedureCallでの簡易オプティミスティック・バージョン・ロック値の指定方法

オプティミスティック・バージョン・ロックを使用する場合は、一般的にバージョン・フィールドを更新する役割をTopLinkに委譲します。

あるいは、ストアド・プロシージャを使用して、すべての作成、読取り、更新および削除操作のバージョン・フィールドの手動更新を選択することもできます。

オプティミスティック・ロックおよびストアド・プロシージャ・コールを使用する場合、ストアド・プロシージャでTopLinkとは別に生成できる単純な連続数値のみ使用できます。タイムスタンプなどの複雑な値を使用する場合は、バージョン・フィールドを更新する役割をTopLinkに委譲する必要があります。

詳細は、16.4.1項「オプティミスティック・バージョン・ロック・ポリシー」を参照してください。

JDBCデータ・タイプを使用したStoredProcedureCallで簡易オプティミスティック・バージョン・ロック値を指定する手順:

  1. 作成、読取り、更新および削除操作用のストアド・プロシージャを作成します。

    各ストアド・プロシージャには、オプティミスティック・ロック・フィールドをチェックおよび更新する役割があります。データベース内では単純な連続する数値です。

    例109-50は、更新操作用の標準的なストアド・プロシージャを示します。

    例109-50 簡易オプティミスティック・バージョン・ロックを使用した更新操作用のストアド・プロシージャ

    PROCEDURE Update_Employee (
        P_EMP_ID NUMBER,
        P_SALARY NUMBER,
        P_END_DATE DATE,
        P_MANAGER_ID NUMBER,
        P_START_DATE DATE,
        P_F_NAME VARCHAR2,
        P_L_NAME VARCHAR2,
        P_GENDER VARCHAR2,
        P_ADDR_ID NUMBER,
        P_VERSION NUMBER,
        P_START_TIME DATE,
        P_END_TIME DATE,
        O_ERROR_CODE OUT NUMBER) AS
    BEGIN
    Update SALARY set SALARY = P_SALARY WHERE (EMP_ID = P_EMP_ID);
    Update EMPLOYEE set END_DATE = P_END_DATE, MANAGER_ID = P_MANAGER_ID, VERSION = P_VERSION + 1, 
    START_DATE = P_START_DATE, F_NAME = P_F_NAME, L_NAME = P_L_NAME, GENDER = P_GENDER, ADDR_ID 
    = P_ADDR_ID where ((EMP_ID = P_EMP_ID) and (VERSION = P_VERSION));
    O_ERROR_CODE := SQL%ROWCOUNT;
    END;
    
  2. それぞれの作成、読取り、更新および削除カスタム・ストアド・プロシージャについてStoredProcedureCallを作成します。

    例109-51は、例109-50の更新ストアド・プロシージャ用のStoredProcedureCallを示します。

    例109-51 更新ストアド・プロシージャ用のStoredProcedureCall

    UpdateObjectQuery updateQuery = new UpdateObjectQuery();
    call = new StoredProcedureCall();
    call.setUsesBinding(true);
    call.setProcedureName("Update_Employee");
    call.addNamedArgument("P_EMP_ID", "EMP_ID");
    call.addNamedArgument("P_SALARY", "SALARY");
    call.addNamedArgument("P_END_DATE", "END_DATE");
    call.addNamedArgument("P_MANAGER_ID", "MANAGER_ID");
    call.addNamedArgument("P_START_DATE", "START_DATE");
    call.addNamedArgument("P_F_NAME", "F_NAME");
    call.addNamedArgument("P_L_NAME", "L_NAME");
    call.addNamedArgument("P_GENDER", "GENDER");
    call.addNamedArgument("P_ADDR_ID", "ADDR_ID");
    call.addNamedArgument("P_VERSION", "VERSION");
    call.addNamedArgument("P_START_TIME", "START_TIME");
    call.addNamedArgument("P_END_TIME", "END_TIME");
    call.addNamedOutputArgument("O_ERROR_CODE", "O_ERROR_CODE", Long.class);
    updateQuery.setCall(call);
    

    詳細は、次を参照してください。

  3. TopLinkディスクリプタ問合せマネージャを構成して、StoredProcedureCallオブジェクトを作成、読取り、更新および削除操作に使用します。

    例109-52は、ディスクリプタ・カスタマイザ・クラスを使用し、例109-51の更新StoredProcedureCallでTopLinkディスクリプタ問合せマネージャを更新する方法を示します。

    例109-52 StoredProcedureCallを使用したTopLinkディスクリプタ問合せマネージャの構成

    import oracle.toplink.tools.sessionconfiguration.DescriptorCustomizer;
    import oracle.toplink.descriptors.ClassDescriptor;
    
    public class EmployeeDescriptorCustomizer implements DescriptorCustomizer {
    
        public void customize(ClassDescriptor descriptor) {
            descriptor.getQueryManager().setUpdateQuery(updateQuery);
        }
    }
    

    詳細は、次を参照してください。

  4. エラーを処理するためにStoredProcedureCall出力パラメータ・イベントを定義します。


    注意:

    Oracleデータベースでは、ストアド・プロシージャをコールする際、行数は保持されません。出力パラメータを使用して行数が必ず返されるようにしてください。SessionイベントoutputParametersDetectedを使用すると、行数がチェックされてエラーがスローされます。または、このストアド・プロシージャによって、行数をチェックしてエラーをスローすることもできます。

    詳細は、109.5.5項「JDBCまたはPL/SQLデータ・タイプを使用したStoredProcedureCall出力パラメータ・イベントの構成方法」を参照してください。

109.5.5 JDBCまたはPL/SQLデータ・タイプを使用したStoredProcedureCall出力パラメータ・イベントの構成方法

TopLinkでは、出力パラメータ・イベントをサポートするデータベース用に出力パラメータ・イベントが管理されます。たとえば、アプリケーションがエラー条件のチェックを必要としていることを示すエラー・コードがストアド・プロシージャから返されると、セッション・イベントoutputParametersDetectedが発生し、アプリケーションは出力パラメータを処理することができます。

JDBCまたはPL/SQLデータ・タイプを使用したStoredProcedureCall出力パラメータ・イベントの構成手順:

  1. JDBC引数またはPL/SQL引数あるいはその両方を使用して、StoredProcedureCallを作成します。例109-53は、JDBC引数を使用したStoredProcedureCallを示します。

    詳細は、次を参照してください。

    例109-53 ストアド・プロシージャ

    PROCEDURE Update_Employee (
        P_EMP_ID NUMBER,
        P_SALARY NUMBER,
        P_END_DATE DATE,
        P_MANAGER_ID NUMBER,
        P_START_DATE DATE,
        P_F_NAME VARCHAR2,
        P_L_NAME VARCHAR2,
        P_GENDER VARCHAR2,
        P_ADDR_ID NUMBER,
        P_VERSION NUMBER,
        P_START_TIME DATE,
        P_END_TIME DATE,
        O_ERROR_CODE OUT NUMBER) AS
    BEGIN
    Update SALARY set SALARY = P_SALARY WHERE (EMP_ID = P_EMP_ID);
    Update EMPLOYEE set END_DATE = P_END_DATE, MANAGER_ID = P_MANAGER_ID, VERSION = P_VERSION + 1, 
    START_DATE = P_START_DATE, F_NAME = P_F_NAME, L_NAME = P_L_NAME, GENDER = P_GENDER, ADDR_ID 
    = P_ADDR_ID where ((EMP_ID = P_EMP_ID) and (VERSION = P_VERSION));
    O_ERROR_CODE := SQL%ROWCOUNT;
    END;
    
  2. outputParametersDetectedイベントを処理するSessionEventListenerを作成します(例109-54を参照)。

    SessionEventListenerを作成する簡単な方法は、oracle.toplink.sessions.SessionEventAdapterをサブクラス化することです。使用する特定のSessionEventListenerメソッドをオーバーライドするのみで済みます。

    例109-54では、SessionEventメソッドgetPropertyは、ERROR_CODEの引数の値を使用しています。このプロパティ名およびそのデータ・タイプは、StoredProcedureCallメソッドaddNamedOutputArgumentで定義されています。

    例109-54 outputParametersDetected EventのSessionEventListener

    import oracle.toplink.sessions.SessionEventAdapter;
    import oracle.toplink.sessions.SessionEvent;
    
    public class OptimisticLockListener extends SessionEventAdapter {
        public OptimisticLockListener() {
        }
    
        public void outputParametersDetected(SessionEvent event) {
            DatabaseQuery query = event.getQuery();
            if ((query != null) && query.isObjectLevelModifyQuery()) {
                Number rowcount = new Integer(1);
                if (event.getResult() instanceof Map) {
                    rowcount = (Number)((Map)event.getResult()).get("O_ERROR_CODE");
                }
                if (rowcount.longValue() <= 0) {
                    if (query.isDeleteObjectQuery()) {
                        DeleteObjectQuery deleteQuery = (DeleteObjectQuery)query;
                        throw OptimisticLockException.objectChangedSinceLastReadWhenDeleting(
                                                      deleteQuery.getObject(), deleteQuery);
                    }
                    else if (query.isWriteObjectQuery()) {
                        WriteObjectQuery updateQuery = (WriteObjectQuery)query;
                        throw OptimisticLockException.objectChangedSinceLastReadWhenUpdating(
                                                      updateQuery.getObject(), updateQuery);
                    }
                }
            }
        }
    }
    
  3. セッション・イベント・マネージャにSessionEventListenerインスタンスを追加します(例109-55を参照)。

    この手順はストアド・プロシージャを実行する前に行う必要があります。

    詳細は、87.2.5項「セッション・イベント・マネージャによるセッション・イベントの管理」を参照してください。

    例109-55 セッション・イベント・マネージャへのSessionEventListenerの追加

    getSession().getEventManager().addListener(new OptimisticLockListener());
    
  4. 問合せを実行します。

    エラーおよびoutputParametersDetectedタイプのSessionEventが発生した場合、TopLinkではSessionEventListenerに通知します。

109.5.6 StoredProcedureCallの使用について

TopLinkでは、out引数(および入出力引数のoutの値)用のPL/SQLデータ・タイプを、表109-1に示すJavaデータ・タイプに自動的に変換します。

表109-1 TopLink PL/SQLのJavaデータ・タイプへの変換: out引数および入出力引数のoutの値

PL/SQLデータ・タイプ OraclePLSQLTypes列挙タイプ Javaタイプ

BINARY_INTEGER

BinaryInteger

java.math.BigDecimal

BOOLEAN

PLSQLBoolean

java.lang.Integer

DEC

Dec

java.math.BigDecimal

INT

Int

java.math.BigDecimal

NATURAL

Natural

java.math.BigDecimal

NATURALN

NaturalN

java.math.BigDecimal

PLS_INTEGER

PLSQLInteger

java.math.BigDecimal

POSITIVE

Positive

java.math.BigDecimal

POSITIVEN

PositiveN

java.math.BigDecimal

SIGNTYPE

SignType

java.lang.Integer


Javaタイプのサイズと精度がPL/SQLタイプに適している場合、Javaタイプの値をPL/SQLのin引数(または入出力引数のin値)に使用できます。


注意:

OUTまたはINOUTパラメータを持つStoredProcedureCallを使用する際に、DatabaseQueryのメソッドbindAllParametersを使用する必要がなくなりました。ただし、すべてのOUTおよびINOUTパラメータのJavaタイプを必ず指定する必要があります。これを指定しないと、デフォルトとしてタイプStringが使用されることに注意してください。

109.6 StoredFunctionCallの使用

TopLinkの式フレームワークを使用すると、複雑な問合せをオブジェクト・レベルで定義できます。アプリケーションでより複雑な問合せ、またはデータベースに付属の既存のストアド・ファンクションを起動する問合せを必要とする場合は、JDBCおよびPL/SQLの両方のデータ・タイプを使用してStoredFunctionCallオブジェクトを定義し、DatabaseQueryのコンテキストでストアド・ファンクションを起動できます。

すべてのデータベースがストアド・ファンクションを提供しているわけではありません。

例109-56では、StoredFunctionCallのメソッドsetProcedureNameを使用してストアド・ファンクションの名前が設定されていることに注意してください。

例109-56 StoredFunctionCallの作成

StoredFunctionCall functionCall = new StoredFunctionCall();
functionCall.setProcedureName("CHECK_VALID_EMPLOYEE");
functionCall.addNamedArgument("EMP_ID");
functionCall.setResult("FUNCTION_RESULT", String.class);
ValueReadQuery query = new ValueReadQuery();
query.setCall(functionCall);
query.addArgument("EMP_ID");
Vector args = new Vector();
args.addElement(new Integer(44));
String valid = (String) session.executeQuery(query, args);

109.6.1 StoredFunctionCallの使用について

一般的に、ストアド・プロシージャとストアド・ファンクションのどちらにおいても、入力パラメータ、出力パラメータおよび入出力パラメータを指定できます。詳細は、109.5項「StoredProcedureCallの使用」を参照してください。ただし、ストアド・プロシージャでは値を返す必要はありませんが、ストアド・ファンクションでは必ず値を1つ返します。

StoredFunctionCallクラスは、StoredProcedureCallを拡張して新しく1つのメソッドsetResultを追加したものです。このメソッドを使用して、ストアド・ファンクションの戻り値の、TopLinkによる保存先の名前(または名前とタイプの両方)を指定します。

TopLinkでStoredFunctionCallをプリコンパイルする際には、そのSQLが検証され、次の場合にValidationExceptionがスローされます。

  • ストアド・ファンクションが現在のプラットフォームでサポートされていない場合。ストアド・ファンクションは、Oracleでのみサポートされています。

  • 戻りタイプを指定しなかった場合。

109.7 JPQL(Java Persistence Query Language)コールの使用

TopLinkの式フレームワークを使用すると、複雑な問合せをオブジェクト・レベルで定義できます。

あるいは別の方法として、カスタムJPQL文字列をJPQLコール・オブジェクトに指定し、そのオブジェクトを任意の問合せに対して指定することもできます。詳細は、『EclipseLink Developer's Guide』の「Using Java Persistence Query Language (JPQL) Calls」(http://wiki.eclipse.org/Using_Basic_Query_API_%28ELUG%29#Using_Java_Persistence_Query_Language_.28JPQL.29_Calls)を参照してください。

109.8 EISインタラクションの使用

EISルート・ディスクリプタの場合は、EISインタラクションを定義してEISに対してメソッドを起動できます。

TopLinkでは、EISインタラクションを表すためにoracle.toplink.eis.interactions.EISInteractionのインスタンスを使用します。これらのクラスにはCallインタフェースが実装されているため、Callを使用できるところではどこでもこれらのクラスを使用できます。

表109-2は、TopLinkがサポートするEISインタラクションのタイプを示します。

表109-2 EISインタラクション

EISインタラクションのタイプ 説明

IndexedInteraction

索引付きレコードを使用するJCAインタラクションのコールの仕様定義です。位置による引数から入力レコードと出力レコードを作成します。

MappedInteraction

マップされたレコードを使用するJCAインタラクションのコールの仕様定義です。名前による引数から入力レコードと出力レコードを作成します。

XMLInteraction

EISプロジェクトに関連付けられたXMLスキーマ文書(XSD)によって定義されたXMLレコードを使用するJCAインタラクションのコールの仕様を定義する、MappedInteractionのインスタンスを指定します(詳細は、5.6.3項「XMLスキーマのインポート方法」を参照)。

QueryStringInteraction

問合せ文字列を使用するJCAインタラクションのコールの仕様を定義するMappedInteractionのインスタンスを指定します。問合せ文字列の引数には、接頭辞としてシャープ記号(#)を付けます。

XQueryInteraction

XQueryを使用するJCAインタラクションのコールの仕様を定義するXMLInteractionのインスタンスを指定します。問合せの引数のXQueryを変換します。


TopLinkを使用して、基本的な永続性操作(insertupdatedeleteread objectread allまたはdoes exist)ごとに1つのインタラクションを定義できます。これにより、EISマップ・オブジェクトに問い合せてそれを変更する際に、TopLinkランタイムでは適切なEISインタラクションが使用されます。詳細は、76.5項「基本的な永続性操作用のカスタムEISインタラクションの構成」を参照してください。

また、TopLinkを使用して、読取り問合せおよびすべて読取り問合せのための名前付き問合せとしてインタラクションを定義することもできます。これらの問合せは、基本的な永続性操作の目的ではコールされません。これら追加の名前付き問合せは、特殊な目的のためにアプリケーション内からコールできます。詳細は、119.7.1.8項「名前付き問合せに関するEISインタラクションの作成」を参照してください。

109.9 例外の処理

問合せにおける例外は、ほとんどがデータベース操作の失敗によるデータベース例外です。書込み操作の場合は、オプティミスティック・ロックを使用するアプリケーションでの書込み、更新または削除操作で、OptimisticLockExceptionがスローされることもあります。これらの例外を捕捉するには、すべてのデータベース操作をtry-catchブロック内で実行します。

    try {
        List employees = session.readAllObjects(Employee.class);
    }
    catch (DatabaseException exception) {
        // handle exception
    }

TopLinkアプリケーションの例外の詳細は、付録A「TopLinkアプリケーションのトラブルシューティング」を参照してください。

109.10 コレクション問合せの結果の処理

TopLinkでは、DataReadQueryおよびReadAllQueryのサブクラスのすべてにuseCollectionClassメソッドがあります。このメソッドを使用して問合せを構成し、結果を、CollectionまたはMapの任意の具象インスタンスとして返すようにします。問合せには、ArrayList、HashSet、HashMap、TreeSetなど、様々なコレクション・クラス・タイプを設定できます。

109.11 レポート問合せの結果の処理

表109-3は、ReportQueryが結果を返す方法を構成するために使用できるReportQueryのメソッドを示します。

デフォルトでは、ReportQueryによって、ReportQueryResultオブジェクトのCollectionが返されます。

表109-3 レポート問合せの結果のオプション

メソッド 問合せの戻り値 説明

setShouldReturnSingleAttribute

Collection

ReportQueryResultにラップされない属性を1つ返します。このオプションは、ReportQueryの返す属性が1つのみであることがわかっている場合に使用します。

setShouldReturnSingleResult

ReportQueryResult

CollectionにもMapにもラップされていない最初のReportQueryResultオブジェクトのみを返します。このオプションは、ReportQueryで1行のみが返されることがわかっている場合に使用してください。

setShouldReturnSingleValue

Object

単一の値のみを返します。このオプションは、ReportQueryで1行のみが返され、含まれる属性が1つしかないことがわかっている場合に使用してください。


詳細は、次を参照してください。