ヘッダーをスキップ
Oracle TopLink開発者ガイド
10g(10.1.3.1.0)
B31861-01
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

94 基本問合せAPIの使用

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

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

セッション問合せの使用

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


注意:

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

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

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

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

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

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

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

session.readObject(MyDomainObject.class);

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

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

例94-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"));

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

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

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

例94-2 式を使用したreadAllObjects

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

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

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


注意:

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

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

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

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

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

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

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

例94-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);

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

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

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

// Read a Vector of all the current employees in the database.
Vector employees = (Vector) 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);

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

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

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

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

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

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

DatabaseQuery問合せの使用

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

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

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

基本DatabaseQuery読取り操作

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

例94-5 単純なReadAllQuery

// This example returns a Vector 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
Vector employees = (Vector) session.executeQuery(query);

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

例94-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");

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

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

例94-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();
Vector employees = (Vector) session.executeQuery(query);
list.addAll(employees);

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

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

例94-8では、カナダ人従業員の合計給与と平均給与が都市別に報告されます。

例94-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"));
Vector reports = (Vector) session.executeQuery(query);

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


注意:

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

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

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

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

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

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

例94-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);

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

例94-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
ReadObjectQuery query = new ReadObjectQuery(Employee.class);
query.setExampleObject(employee);

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

QueryByExamplePolicyの定義

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

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

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

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

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

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

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

例94-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);
Vector results = (Vector) session.executeQuery(query);

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

例94-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);
Vector results = (Vector) session.executeQuery(query);

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

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

例94-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);
Vector results = (Vector) session.executeQuery(query);

読取り順序の指定

順序付けは、DatabaseQueryの一般的なオプションです。TopLink Workbenchの「順序」タブを使用し、JavaコードでReadAllQueryaddOrderingaddAscendingOrderingaddDescendingOrderingメソッドを使用して、返されるオブジェクトのコレクションの順序を指定します。属性名または問合せキーと式に基づいた順序を適用できます。

例94-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");
Vector employees = (Vector) session.executeQuery(query);

例94-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"));
Vector employees = (Vector) session.executeQuery(query);

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

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

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

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

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

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

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

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

返される最大行の指定

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

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

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

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

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

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

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

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

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

例94-19 DatabaseQueryタイムアウト

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

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

バッチ読取りの使用

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

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

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

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

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

詳細は、「読取り例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);
    …
    
    
  • ディスクリプタのマッピング・レベルでバッチ読取りを追加します。TopLink Workbenchまたはディスクリプタ修正メソッドを使用して、ディスクリプタのリレーションシップ・マッピングでsetUsesBatchReading APIを追加します。

    例:

    public static void amendTradeDescriptor(Descriptor theDescriptor) {
        OneToOneMapping productOneToOneMapping =        theDescriptor.getMappingForAttributeName("product");
        productOneToOneMapping.setUsesBatchReading(true);
    }
    
    

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

結合読取りの使用

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

結合された1つ以上の属性を問合せに追加するには、TopLink WorkbenchまたはJavaを使用できます。

TopLink Workbenchの使用

TopLink Workbenchを使用して、結合された1つ以上の属性を問合せに追加するには、名前付き問合せ(「名前付き問合せの最適化の構成」を参照)を定義する際に、結合属性を構成します。1対多のマップ属性についての結合式を使用してObjectLevelReadQueryを作成する場合は、TopLink Workbenchは使用できません。この場合はJavaを使用する必要があります。

Javaの使用

ObjectLevelReadQuery APIを使用して、1対1および1対多のリレーションシップに結合属性を追加できます。

ObjectLevelReadQueryのメソッドaddJoinedAttribute(Expression attributeExpression)を使用すると、結合式を問合せに追加できます。このメソッドを使用して、ネストされた結合を含む、複数の結合属性を1対1および1対多のリレーションシップに追加できます。ソースおよびターゲットは、同じクラス・タイプにすることができます。ObjectLevelReadQueryのメソッドaddJoinedAttributeは、多対多のマップ属性についての結合式では、使用できません。

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

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

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

例94-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"));

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

例94-21 複数属性の結合読取りを行うSQL

SELECT DISTINCT
    t2.VERSION, t3.EMP_ID, t2.GENDER, t3.SALARY, t2.EMP_ID, t2.F_NAME, t2.L_NAME,
    t2.MANAGER_ID, t2.ADDR_ID, t2.END_DATE, t2.START_DATE, t2.END_TIME,
    t2.START_TIME, t0.VERSION, t1.EMP_ID, t0.GENDER, t1.SALARY, t0.EMP_ID,
    t0.F_NAME, t0.L_NAME, t0.MANAGER_ID, t0.ADDR_ID, t0.END_DATE, t0.START_DATE,
    t0.END_TIME, t0.START_TIME
FROM
    SALARY t3, EMPLOYEE t2, SALARY t1, EMPLOYEE t0
WHERE
    ((t3.EMP_ID = t2.EMP_ID) AND
     ((t0.MANAGER_ID (+) = t2.EMP_ID) AND
     (t1.EMP_ID (+) = t0.EMP_ID)))

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

例94-22 1つの属性の結合読取り

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

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

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

書込み問合せの概要

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

例94-23 WriteObjectQueryの使用

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

例94-24 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);

UpdateAllQuery

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

例94-25 UpdateAllQueryの使用

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

同一のSQL文では複数の表を更新できないため、UpdateAllQueryでは、複数の表にわたるオブジェクト、または継承をサポートしていません。また、UpdateAllQueryは、独自のトランザクションから実行する必要があります。このため、作業ユニットにはこの問合せのみを含めてください。UnitOfWorkのメソッドexecuteQueryを使用します。

非JTAトランザクションの場合、TopLinkでは作業ユニットとセッション実行がサポートされます。JTAトランザクションの場合、作業ユニットのみがサポートされます(セッション実行はサポートされません)。トランザクションの詳細は、第97章「TopLinkトランザクションの概要」を参照してください。

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

UpdateAllQueryでは、単方向の1対1リレーションシップのみがサポートされます。ダイレクト・マッピングは完全にサポートされ、集約マッピングは部分的にサポートされます(第IX部「マッピング」を参照)。


注意:

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

これらの問合せでは外部キーの更新がサポートされないため、これらの問合せを使用して外部キー・フィールドにNULLを設定することはできません。

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

非カスケード書込み問合せ

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

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

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

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


    注意:

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

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

// 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);

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

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

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

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

// 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);
   }
}


注意:

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

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

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

DataReadQueryの使用

例94-28に示すように、DataReadQueryを使用すると、結果セットを表すDatabaseRowsCollectionを返す選択SQL文字列を実行できます。

例94-28 DataReadQueryの使用

DataReadQuery dataReadQuery = new DataReadQuery();
dataReadQuery.setSQLStatement(sqlStatement);

// queryResults is a Vector of DatabaseRow objects
Vector queryResults = (Vector)session.executeQuery(dataReadQuery);

DirectReadQueryの使用

例94-29に示すように、DirectReadQueryは、データの1列(1つのフィールド)を読み取り、結果セットを表すDatabaseRowsCollectionを返すために使用できます。

例94-29 DirectReadQueryの使用

DirectReadQuery directReadQuery = new DirectReadQuery();
directReadQuery.setSQLStatement(sqlStatement);

// queryResults is a Vector of DatabaseRow objects
Vector queryResults = (Vector)session.executeQuery(directReadQuery);

ValueReadQueryの使用

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

例94-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インジェクション攻撃に対してアプリケーションが脆弱になります。


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

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

例94-31 DataModifyQueryの使用

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

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

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

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

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

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

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

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

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

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

警告:

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


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

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

問合せにおけるカスタムEJB QLの使用方法の詳細は、「EJB QLコールの使用」を参照してください。

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

例94-34 EJB QL

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

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

例94-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
Vector returnedObjects = (Vector)session.executeQuery(query, arguments);

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

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

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

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

または、すべての問合せに対してログイン・レベルでパラメータ使用のSQLおよびバインドを構成できます(「JDBCオプションの構成」を参照)。

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


注意:

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

名前付き問合せの使用

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

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

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

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

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

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

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

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

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

SQLコールの使用

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

また、DatabaseQueryに直接SQL文字列を指定することもできます。詳細は、「DatabaseQueryにおけるカスタムSQL文字列の指定」を参照してください。

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

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

SQLCallの使用

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

SQL文字列には、複雑なSQL問合せ、ストアド・プロシージャ・コールまたはストアド・ファンクション・コールを指定できます。入力、出力、および入出力パラメータを指定できます。

SQLCallは、セッション問合せメソッド(例94-39を参照)またはDatabaseQueryを通じて起動できます。

例94-39 カスタムSQLを使用したセッション読取り問合せ

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


警告:

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


TopLinkでは、SQLCallのカスタムSQL文字列のトークンの先頭に1つ以上のシャープ記号(#)が付いている場合は、そのトークンがパラメータであるものとみなします。次の各項で説明するように、問合せAPIを使用して、これらのパラメータに値をバインドすることができます。

SQLCall入力パラメータの指定

例94-40において、last_nameは、その先頭にシャープ記号(#)を1つ付けることで、入力パラメータとして指定されています。例94-41では、問合せの実行時にこの入力パラメータに値をバインドする方法を示します。

例94-40 入力パラメータ(接頭辞#付き)を持つSQLCallの指定

SQLCall sqlCall = new SQLCall(
    "INSERT INTO EMPLOYEE (L_NAME) VALUES (#last_name)");

例94-41 入力パラメータを持つSQLCallの実行

DataModifyQuery query = new DataModifyQuery();
query.setCall(sqlCall);
query.addArgument("last_name");   // input

Vector arguments = new Vector();
arguments.add("MacDonald");
session.executeQuery(query, arguments);

SQLCall出力パラメータの指定

例94-42において、employee_idは、その先頭にシャープ記号を3つ(###)付けることで、出力パラメータとして指定されています。出力パラメータのタイプは、SQLCallのメソッドsetCustomSQLArgumentTypeを使用して指定します。last_nameは、この例でも、その先頭にシャープ記号(#)を付けることで入力パラメータとして指定されています。

例94-42 出力パラメータ(接頭辞###付き)を持つSQLCallの指定

SQLCall sqlCall = new SQLCall("begin;
    INSERT INTO EMPLOYEE (L_NAME) VALUES (#L_NAME) RETURNING EMP_ID INTO ###employee_id;
    end");
sqlCall.setCustomSQLArgumentType("employee_id", Integer.class);

例94-43 出力パラメータを持つSQLCallの実行

ValueReadQuery query = new ValueReadQuery();
query.setCall(sqlCall);
query.addArgument("last_name");   // input

Vector args = new Vector();
args.add("MacDonald");

Number employeeID = (Number)getSession().executeQuery(query, args);

タイプCURSORとして宣言された出力パラメータの結果を取得することもできます。

SQLCall入出力パラメータの指定

例94-44において、in_outは、その先頭にシャープ記号を4つ(####)付けることで、入出力パラメータとして指定されています。入力値のタイプによって、出力値のタイプが決まります。この例では、String(MacDonald)が渡され、EMP_IDの出力値がStringとして返されます。

例94-44 入出力パラメータ(接頭辞####付き)の指定

SQLCall sqlCall = new SQLCall(
    "INSERT INTO EMPLOYEE (L_NAME) VALUES (####in_out) RETURNING EMP_ID INTO ####in_out");

例94-45 入出力パラメータを持つSQLCallの実行

ValueReadQuery query = new ValueReadQuery();
query.setCall(sqlCall);
query.addArgument("in_out");   // input and outpu

Vector args = new Vector();
args.add("MacDonald");

Number employeeID = (Numbere)getSession().executeQuery(query, args);

StoredProcedureCallの使用

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

例94-46 ストアド・プロシージャを使用したすべて読取り問合せ

ReadAllQuery readAllQuery = new ReadAllQuery();
call = new StoredProcedureCall();
call.setProcedureName("Read_All_Employees");
call.useNamedCursorOutputAsResultSet("RESULT_SET");
readAllQuery.setCall(call);
Vector employees = (Vector) session.executeQuery(readAllQuery);


StoredProcedureCallを使用すると、次のことが可能になります。


注意:

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

入力パラメータの指定

例94-47では、StoredProcedureCallのメソッドaddNamedArgumentを使用して、入力パラメータとしてパラメータPOSTAL_CODEを指定し、その値をメソッドaddNamedArgumentValueに指定できます。

例94-47 入力パラメータを使用したストアド・プロシージャ・コール

StoredProcedureCall call = new StoredProcedureCall();
call.setProcedureName("CHECK_VALID_POSTAL_CODE");
call.addNamedArgument("POSTAL_CODE");
call.addNamedArgumentValue("POSTAL_CODE", "L5J1H5");
call.addNamedOutputArgument(
    "IS_VALID",    // procedure parameter name
    "IS_VALID",    // out argument field name
    Integer.class  // Java type corresponding to type returned by procedure
);
ValueReadQuery query = new ValueReadQuery();
query.setCall(call);
Number isValid = (Number)session.executeQuery(query);

出力パラメータの指定

出力パラメータを使用すると、ストアド・プロシージャから追加の情報が返されます。オブジェクトの作成に必要なすべてのフィールドが返されれば、出力パラメータを使用してReadObjectQueryを定義できます。

例94-48では、StoredProcedureCallのメソッドaddNamedOutputArgumentを使用して、パラメータIS_VALIDを出力パラメータとして指定します。

例94-48 出力パラメータを使用したストアド・プロシージャ・コール

StoredProcedureCall call = new StoredProcedureCall();
call.setProcedureName("CHECK_VALID_POSTAL_CODE");
call.addNamedArgument("POSTAL_CODE");
call.addNamedOutputArgument(
    "IS_VALID",    // procedure parameter name
    "IS_VALID",    // out argument field name
    Integer.class  // Java type corresponding to type returned by procedure
);
ValueReadQuery query = new ValueReadQuery();
query.setCall(call);
query.addArgument("POSTAL_CODE");
Vector parameters = new Vector();
parameters.addElement("L5J1H5");
Number isValid = (Number)session.executeQuery(query,parameters);


注意:

データを返す出力パラメータの使用をサポートしていないデータベースもあります。ただし、このようなデータベースは一般的にストアド・プロシージャからの結果セットの返却をサポートしているため、出力パラメータを必要としません。

Oracleデータベースを使用している場合、TopLinkのカーソルとストリームの問合せ結果を使用できます。

入出力パラメータの指定

例94-49では、StoredProcedureCallのメソッドaddNamedInOutputArgumentValueへの入出力パラメータとしてパラメータLENGTHを指定するとともに、その値を指定してストアド・プロシージャに渡します。この引数の値を指定しない場合は、メソッドaddNamedInOutputArgumentを使用します。

例94-49 入出力パラメータを使用したストアド・プロシージャ・コール

StoredProcedureCall call = new StoredProcedureCall();
call.setProcedureName("CONVERT_FEET_TO_METERs");
call.addNamedInOutputArgumentValue(
    "LENGTH",          // procedure parameter name
    new Integer(100),  // in argument value
    "LENGTH",          // out argument field name
    Integer.class      // Java type corresponding to type returned by procedure
)
ValueReadQuery query = new ValueReadQuery();
query.setCall(call);
Integer metricLength = (Integer)session.executeQuery(query);

出力パラメータ・イベントの使用

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

例94-50 リセット・セットと出力パラメータのエラー・コードを使用したストアド・プロシージャ

StoredProcedureCall call = new StoredProcedureCall();
call.setProcedureName("READ_EMPLOYEE");
call.addNamedArgument("EMP_ID");
call.addNamedOutputArgument(
    "ERROR_CODE",  // procedure parameter name
    "ERROR_CODE",  // out argument field name
    Integer.class  // Java type corresponding to type returned by procedure
);
call.useNamedCursorOutputAsResultSet("RESULT_SET");
ReadObjectQuery query = new ReadObjectQuery();
query.setCall(call);
query.addArgument("EMP_ID");
ErrorCodeListener listener = new ErrorCodeListener();
session.getEventManager().addListener(listener);
Vector args = new Vector();
args.addElement(new Integer(44));
Employee employee = (Employee)session.executeQuery(query, args);

StoredFunctionCallの使用

StoredProcedureCallを使用して、ストアド・プロシージャをサポートするデータベースで定義されたストアド・プロシージャを起動します。StoredFunctionCallを使用して、ストアド・ファンクションをサポートするデータベース(つまり、DatabasePlatformのメソッドsupportsStoredFunctionstrueを返すデータベース)で定義されたストアド・ファンクションを起動することもできます。

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

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

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

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

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

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

例94-51 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);

EJB QLコールの使用

TopLinkの式フレームワークを使用すると、複雑な問合せをオブジェクト・レベルで定義できます。あるいは別の方法として、カスタムEJB QL文字列をEJB QL Callオブジェクトに指定し、そのCallオブジェクトを任意の問合せに対して指定することもできます。

また、DatabaseQueryに直接EJB QL文字列を指定することもできます。詳細は、「DatabaseQueryにおけるカスタムEJB QL文字列の指定」を参照してください。

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

EJB QL問合せは、セッション問合せメソッドまたはDatabaseQueryを通じて起動できます。

例94-52 カスタムEJB QLを使用したセッション読取り問合せ

Vector theObjects = (Vector)aSession.readAllObjects(
    EmployeeBean.class,
    new EJBQLCall("SELECT OBJECT (emp) from EmployeeBean emp"));

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

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

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

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

表94-1 EISインタラクション

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

IndexedInteraction

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

MappedInteraction

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

XMLInteraction

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

QueryStringInteraction

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

XQueryInteraction

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


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

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

例外の処理

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

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

TopLinkアプリケーションの例外の詳細は、第14章「TopLink Workbenchエラー参照」を参照してください。

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

TopLinkでは、DataReadQueryおよびReadAllQueryのすべてのサブクラスに対して、useCollectionClassメソッドを用意しています。これらを使用して問合せを構成し、結果をCollectionまたはMapの具象インスタンスとして返すことができます。

コレクション問合せの結果の構成をマッピングのコンテナ・ポリシーと混同しないようにしてください(「コンテナ・ポリシーの構成」を参照)。これらの間には何の関係もありません。コレクション問合せの結果の構成により、TopLinkで特定の問合せから複数オブジェクトの結果を返す方法が決まります。マッピングのコンテナ・ポリシーは、ユーザーのドメイン・オブジェクトがコレクションを含むデータ・メンバーを実装する方法をTopLinkに指示します。

たとえば、クラスEmployeeとデータ・メンバーphoneNumbersを考えてみます。Employeeのユーザー実装では、getPhoneNumbersメソッドがVectorを返すとします。TopLink Workbenchを使用して、phoneNumbersデータ・メンバーを1対多のマッピングとしてマップします。マッピングのコンテナ・ポリシーを構成し、マッピングに、Vectorに格納されたデータ・メンバーの値(多数のPhoneNumberオブジェクト)が含まれるようにします。これは、Employeeのユーザー実装に対応しています。

PhoneNumberDescriptorQueryManagerに対する、localPhoneNumbersという名前のReadAllQueryを定義します。localPhoneNumbers問合せは、引数としてEmployeeオブジェクトのIDをとり、そのphoneNumbersデータ・メンバーから、市外局番が613の電話番号をすべて返します。

PhoneNumberDescriptorQueryManagerから、この名前付き問合せを取得します。このReadAllQuery上で、useCollectionClassメソッドをArrayListクラスの引数付きでコールします。この問合せをEmployeeのID付きで実行します。この問合せは、EmployeeオブジェクトのphoneNumbersデータ・メンバーから、市外局番が613のPhoneNumberオブジェクトをすべて返します。この結果は、ArrayListとして返されます。

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

表94-2では、ReportQueryが結果を返す方法を構成するために使用できるReportQueryのメソッドをリストしています。

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

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

setShouldReturnSingleAttribute

DatabaseRow

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

setShouldReturnSingleResult

ReportQueryResult

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

setShouldReturnSingleValue

Object

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


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