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

戻る
戻る
 
次へ
次へ
 

110TopLinkの式の概要

TopLinkの式フレームワークを使用すると、ドメイン・オブジェクト・モデルに基づいて問合せの検索基準を指定できます。

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

110.1 式フレームワーク

TopLinkの式フレームワークは、次のクラスを通じてメソッドを提供します。

例110-1は、Expressionクラスの使用方法を示します。

例110-1 Expressionクラスの使用

expressionBuilder.get("lastName").equal("Smith");

例110-2は、ExpressionMathクラスの使用方法を示します。

例110-2 ExpressionMathクラスの使用

ExpressionMath.abs(ExpressionMath.subtract(emp.get("salary"),
emp.get("spouse").get("salary")).greaterThan(10000)

このように機能を分けることで、TopLinkの式は、java.lang.Mathクラスに似た数値演算機能を提供しながらも、ExpressionおよびExpressionMathクラスが必要以上に複雑になることを防ぐことができます。

110.1.1 式とSQLの比較

データベースにアクセスする場合、式は次の点でSQLよりも優れています。

  • データベースが抽象化されるため、式の方が管理が容易です。

  • ディスクリプタまたはデータベース表に変更を加えても、アプリケーションの問合せ構造に影響を与えません。

  • 式では、Javaの通常のコール方法に似せてQueryインタフェースを標準化するため、読みやすさが向上します。たとえば、EmployeeクラスのAddressオブジェクトから通りの名前を取得するのに必要なJavaコードは次のとおりです。

    emp.getAddress().getStreet().equals("Meadowlands");
    

    同じ情報を取得するための式はこれに似ています。

    emp.get("address").get("street").equal("Meadowlands");
    
  • 式を使用すると、読取り問合せによって、同じリレーションシップを共有する2つのクラスの間で問合せを透過的に行うことができます。これらのクラスがデータベース内の複数の表に格納されている場合、適切な結合文が自動的に生成され、両方の表から情報が返されます。

  • 式は複雑な操作を単純化します。たとえば、次のJavaコードは、Meadowlandsに住み、給与が10,000を超える従業員をすべて取得します。

    ExpressionBuilder emp = new ExpressionBuilder();
    Expression exp = emp.get("address").get("street").equal("Meadowlands");
    Vector employees = session.readAllObjects(Employee.class,
      exp.and(emp.get("salary").greaterThan(10000)));
    

    このコードから適切なSQLが自動的に生成されます。

    SELECT t0.VERSION, t0.ADDR_ID, t0.F_NAME, t0.EMP_ID, t0.L_NAME, t0.MANAGER_ID, t0.END_DATE, t0.START_DATE, 
    t0.GENDER, t0.START_TIME, t0.END_TIME,t0.SALARY FROM EMPLOYEE t0, ADDRESS t1 WHERE 
    (((t1.STREET = 'Meadowlands')AND (t0.SALARY > 10000)) AND (t1.ADDRESS_ID = t0.ADDR_ID))
    

110.2 式の構成要素

通常、単純な式は次の3つの部分で構成されています。

  1. 属性: 永続クラスのマップ済属性または問合せキーを表します。

  2. 演算子: GreaterThanEqualLikeなどのブール・ロジックを実現する表現方法です。

  3. 定数または比較: オブジェクトの選択に使用される値を参照します。

次のコードを見てみましょう。

expressionBuilder.get("lastName").equal("Smith");

expressionBuilderには、データベースから読み取られる1つ以上のオブジェクトに置き換わります。この例では、expressionBuilderは従業員を表しています。

式を構成する際には、次の構成要素を使用できます。

110.2.1 ブール・ロジック

式では、ANDORNOTなどの標準的なブール演算子が使用されます。複数の式を組み合せて、さらに複雑な式を構成することができます。例110-3は、選択された人によって管理され、予算が1,000,000以上のプロジェクトを問い合せるコードの一部分を示します。

例110-3 式でのブール・ロジックの使用

ExpressionBuilder project = new ExpressionBuilder();
Expression hasRightLeader, bigBudget, complex;
Employee selectedEmp = someWindow.getSelectedEmployee();
hasRightLeader = project.get("teamLeader").equal(selectedEmp);
bigBudget = project.get("budget").greaterThanEqual(1000000);
complex = hasRightLeader.and(bigBudget);
Vector projects = session.readAllObjects(Project.class, complex);

110.2.2 データベース関数および演算子

関数

TopLinkの式では、様々なデータベース関数がサポートされます。次にその一部を示します。

  • toUpperCase

  • toLowerCase

  • toDate

  • decode

  • locate

  • monthsBetween

  • nextDay

  • replace

  • reverse

  • substring

  • translate


注意:

一部の関数はデータベース・プラットフォームに固有です。

データベース関数を使用すると、より柔軟な問合せを定義できます。これらの関数は、SELECT句を使用したレポート問合せの項目で、またはWHERE句を使用した問合せの選択基準の比較で使用できます。例110-4は、SMART、Smith、Smothersなどの複数の姓に一致するコードの一部分を示します。

例110-4 Expression APIによってサポートされているデータベース関数の使用

emp.get("lastName").toUpperCase().like("SM%")

ほとんどの関数は、式のtoUpperCaseなどのメソッドを使用してアクセスできます。

用途の限定されている関数もあります。例110-5に示すように、ascending関数やdescending関数は、結果を昇順または降順に配置するために順序付けの式内でのみ使用します。

例110-5 順序付けデータベース関数の使用

readAllQuery.addOrderBy(expBuilder.get("address").get("city").ascending())

注意:

順序付けはインメモリー問合せではサポートされていません(108.16.2項「インメモリー問合せの使用方法」を参照)。

ReportQuery108.7.5項「レポート問合せ」を参照)では、averageminimummaximumsumなどの集計関数を使用できます。

演算子

演算子は、2つの値を比較する関係演算子です。TopLinkの式では、次の演算子がサポートされています。

  • like

  • notLike

  • equal

  • notEqual

  • lessThan

  • lessThanEqual

  • equalsIgnoreCase

  • greaterThan

  • greaterThanEqual

  • in

  • notIn

  • between

  • notBetween

例110-4は、like演算子の使用方法を示します。

110.2.3 数値演算関数

数値演算関数は、ExpressionMathクラスを通じて使用できます。式における数値演算関数のサポートは、Javaクラスjava.lang.Mathによるサポートに似ています。例110-6は、absおよびsubtractメソッドの使用例を示します。

例110-6 式での数値演算関数の使用

ExpressionMath.abs(ExpressionMath.subtract(emp.get("salary"),emp.get("spouse")
  .get("salary")).greaterThan(10000)

110.2.4 XMLType関数

OracleデータベースXMLType列にマップされたデータに対する問合せを構成する場合は、次の演算子を使用できます。

  • extract: XPath文字列をとり、元のドキュメントのうち、XPathに一致する部分のXMLTypeを返します。

  • extractValue: XPath文字列をとり、XPathが指すノードの内容に基づいて、数値または文字列の値を返します。

  • existsNode: Xpath式をとり、XPathに一致するノードの数を返します。

  • getStringVal: XMLTypeオブジェクトの文字列表現を取得します。

  • getNumberVal: XMLTypeオブジェクトの数値表現を取得します。

  • isFragment: XMLが整形式文書である場合、0に評価します。文書がフラグメントである場合、1に評価します。

例110-7は、問合せにおける抽出演算子の使用方法を示します。

例110-7 XMLType抽出演算子の使用

Expression criteria = builder.get("resume").extract("//education/degree/text()").getStringVal().equal("BCS");
Vector employees = session.readAllObject(Employee.class, criteria);

110.2.5 プラットフォーム関数とユーザー定義関数

ExpressionのメソッドgetFunctionを使用すると、TopLinkで直接サポートされていないデータベース関数にアクセスできます。例110-8は、Expression APIの関数などがサポートされていない場合でも、式内からVacationCreditという名前のデータベース関数にアクセスする方法を示します。

例110-8 Expression APIによってサポートされていないデータベース関数の使用

emp.get("lastName").getFunction("VacationCredit").greaterThan(42)

この式では、次のSQLが生成されます。

SELECT . . . WHERE VacationCredit(EMP.LASTNAME) > 42

Expression APIには、引数を指定できる、他の形式のgetFunctionメソッドもあります。詳細は、『Oracle Fusion Middleware Java API Reference for Oracle TopLink』を参照してください。

ユーザー作成のカスタム関数にアクセスすることもできます。TopLinkのカスタム関数の作成方法の詳細は、110.8項「ユーザー定義関数の作成と使用」を参照してください。

110.2.6 1対1および集約オブジェクトのリレーションシップを表す式

式には、別の永続クラスとの1対1リレーションシップを持つ属性を含めることができます。当然、1対1リレーションシップは単一行を返すSQL結合に変換されます。

例110-9は、従業員の住所のフィールドにアクセスする、コードの一部分を示します。

例110-9 1対1リレーションシップでの式の使用

emp.get("address").get("country").like("S%")

例110-9は、address外部キーに基づいてEMPLOYEE表をADDRESS表に結合し、国名をチェックするという操作に相当します。

これらのリレーションシップは無限にネストさせることができるため、次のような複雑な情報を問い合せることも可能です。

project.get("teamLeader").get("manager").get("manager").get("address").get("street")

110.2.7 結合リレーションシップと複雑なリレーションシップを表す式

1対多、多対多、ダイレクト・コレクション、集約コレクションなどの複雑なリレーションシップに対して問合せを行うことができます。このようなタイプのリレーションシップはオブジェクトごとに単一行を返す結合に直接マップされないため、これらのリレーションシップを表す式は作成方法が複雑です。

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

110.2.7.1 結合について

結合は、2つ以上の表からの行を組み合せるリレーショナル・データベース問合せです。問合せのFROM句に複数の表を記述すると、必ずリレーショナル・データベースでは結合が実行されます。問合せの選択リストでは、これらの表のうちの任意の表から任意の列を選択できます。

内部結合(単純結合とも呼ばれる)は、2つ以上の表の結合で、結合条件を満たす行のみを返します。

外部結合は、内部結合の結果を拡張したものです。外部結合では、結合条件を満たすすべての行を返します。また、1つの表の結合条件がその他の表では満たされない場合には、その表の行の一部またはすべてを返します。外部結合は、左外部結合と右外部結合に分類できます。

  • 表AおよびBの左外部結合を実行する問合せでは、A内の行をすべて返します。B内に一致する行を持たないA内の行すべてに対しては、Bの列を含む選択リストの式に対してnullが返されます。

  • 表AおよびBの左外部結合を実行する問合せでは、B内の行をすべて返します。A内に一致する行を持たないB内の行すべてに対しては、Aの列を含む選択リストの式に対してnullが返されます。

結合式を使用して問合せを行うと、結合が使用され、他のオブジェクトの値、または同じオブジェクトの一部を表す他の表の値をチェックすることができます。これはほとんどの状況でうまくいきますが、リレーションシップの一方が存在しない1対1リレーションシップに対して問合せを行った場合に問題が発生することがあります。

たとえば、EmployeeオブジェクトがAddressオブジェクトを所有しているとします。しかし、Addressが不明な場合、これはオブジェクト・レベルではnullであり、データベース・レベルではnullの外部キーを持つことになります。このリレーションシップを走査する問合せを試行すると、オブジェクトが欠落しているために、予期しない結果が返されます。次の式について考えてみます。

(emp.get("firstName").equal("Steve")).or(emp.get("address"). get("city").equal("Ottawa"))

この場合、住所を持たない従業員は、名前に関係なく結果セットには含まれません。オブジェクト・レベルでは明白ではありませんが、この動作はリレーショナル・データベースの特性の基本となります。

外部結合をサポートしているデータベースでは、外部結合によってこの問題が解決します。この例では、外部結合を使用することで、住所が不明であってもSteveという名前のすべての従業員が結果セットに含まれるという、予期した結果が得られます。

外部結合を実装するには、ExpressionのメソッドgetのかわりにgetAllowingNullを使用します。同様に、ExpressionのメソッドであるanyOfのかわりにanyOfAllowingNoneを使用します。

次に例を示します。

(emp.get("firstName").equal("Steve")).or(
emp.getAllowingNull("address").get("city").equal("Ottawa"))

外部結合のサポートと構文は、データベースとデータベース・ドライバによって大きく異なります。TopLinkでは、ほとんどのデータベースの外部結合がサポートされています。

110.2.7.2 結合でのTopLink Expression APIの使用

選択基準、順序付け(109.2.1.5項「読取り順序の指定」を参照)、レポート問合せ(108.7.5項「レポート問合せ」を参照)、部分オブジェクト(108.7.1.3項「部分オブジェクト問合せ」を参照)、1対1リレーションシップ・マッピング(28.8項「マッピング・レベルでの結合の構成」を参照)および結合読取り(108.7.1.5項「結合読取りとオブジェクト・レベルの読取り問合せ」を参照)など、式を使用する場所ではどこでも結合を使用できます。

表110-1に示すExpression APIを使用して、内部および外部結合式を構成します。

表110-1 結合用のExpression API

Expression API 結合のタイプ マッピングのタイプ

get

inner

1対1

getAllowingNull

外部

1対1

anyOf

inner

1対多、多対多

anyOfAllowingNone

外部

1対多、多対多


1対多または多対多のリレーションシップに対して問合せを行うには、anyOf操作を使用します。その名前が示すように、この操作では問合せ基準を満たすリレーションシップの多くの側面ですべての項目を返す問合せがサポートされます。

例110-10は、給与が10,000ドル未満の従業員を1人以上(1対多リレーションシップを通じて)管理する従業員を返す式を示します。

例110-10 1対多リレーションシップでの式の使用

emp.anyOf("managedEmployees").get("salary").lessThan(10000);

例110-11は、同様の方法で多対多リレーションシップ全体に対して問い合せる方法を示します。

例110-11 多対多リレーションシップでの式の使用

emp.anyOf("projects").equal(someProject)

これらの問合せはSQLに変換されます。SQLでは、DISTINCT句を使用して関連のある表を結合し、重複を排除します。TopLinkでは、例110-10を次のSQLに変換します。

SELECT DISTINCT . . . FROM EMP t1, EMP t2 WHERE
t2.MANAGER_ID = t1.EMP_ID AND t2.SALARY < 10000

ObjectLevelReadyQuery内で1対1および1対多の結合式を使用して、問合せごとに結合を構成できます(108.7.1.5項「結合読取りとオブジェクト・レベルの読取り問合せ」を参照)。

また、マッピング・レベルで結合を構成することもできます(28.8項「マッピング・レベルでの結合の構成」を参照)。


注意:

anyOfを1回コールした場合の結果は、2回コールした場合の結果と異なります。たとえば、市外局番が613で、かつ電話番号が123-4599の従業員を問い合せる場合は、anyOfを1回と一時変数を使用します。市外局番が613の従業員と、電話番号が123-4599の従業員を問い合せる場合は、anyOfを2回コールします。

110.3 パラメータ化された式

リレーションシップ・マッピングは、数多くの様々なオブジェクトのデータを取得するという点で、通常の問合せとは異なります。このような問合せを指定できるようにするには、問合せの実行時に引数を指定します。getParameterおよびgetFieldメソッドを使用して、引数の値を取得します。

パラメータ化された式では、定数ではなく変数に基づいて検索と比較が実行されます。そのため、状況依存の情報を取得する式を作成できます。この手法は、EJBファインダ(108.15項「EJB 2.n CMPファインダ」を参照)を定義する場合に便利です。

パラメータ化された式の場合、リレーションシップ・マッピングが現在のコンテキストに基づいて1つのオブジェクトまたはオブジェクトのコレクションを取得する方法を認識している必要があります。たとえば、EmployeeからAddressへの1対1マッピングでは、Employee表の外部キー情報に基づき、データベースに対して住所を問い合せる必要があります。各マッピングは、マッピングに指定した情報に基づいて自動的に構成される問合せを含んでいます。式を手動で指定するには、マッピング・カスタマイズ・メカニズムを使用します。

パラメータ化された式は、再利用可能な問合せ(108.8項「名前付き問合せ」を参照)の作成に使用できます。

110.3.1 ExpressionのメソッドgetParameter

ExpressionのメソッドgetParameterは、問合せのパラメータとなる式を返します。これにより、ユーザー入力を検索基準に含めた問合せを作成できます。パラメータは、ディスクリプタの行から取得されたフィールドの完全修飾名、または引数の一般名であることが必要です。

この方法で構成したパラメータは現在の問合せ全体に対して有効であるため、このメッセージをすべての式オブジェクトに送信することができます。

例110-12は、カスタム問合せを使用して、名前で従業員を検索する方法を示します。

例110-12 カスタム問合せにおけるパラメータ化された式の使用

Expression firstNameExpression;

ReadObjectQuery query = new ReadObjectQuery(Employee.class);
ExpressionBuilder emp = query.getExpressionBuilder();
firstNameExpression = emp.get("firstName").equal(emp.getParameter("firstName"));
query.setSelectionCriteria(firstNameExpression);
query.addArgument("firstName");
Vector v = new Vector();
v.addElement("Sarah");
Employee e = (Employee) session.executeQuery(query, v);

例110-13は、カスタム問合せを使用して特定の従業員と同じ都市に住む従業員をすべて検索する方法を示します。

例110-13 ネストされ、パラメータ化された式の使用

Expression addressExpression;
ReadObjectQuery query = new ReadObjectQuery(Employee.class);
ExpressionBuilder emp = query.getExpressionBuilder();
addressExpression =
    emp.get("address").get("city").equal(
    emp.getParameter("employee").get("address").get("city"));
query.setName("findByCity");
query.setSelectionCriteria(addressExpression);
query.addArgument("employee");
Vector v = new Vector();
v.addElement(employee);
Employee e = (Employee) session.executeQuery(query, v);

例110-14は、デフォルトではない選択基準を使用して、クラスPolicyHolderからPolicyへの単純な1対多マッピングを取得する方法を示します。POLICY表のSSNフィールドは、HOLDER表のSSNフィールドの外部キーです。

例110-14 マッピングにおけるパラメータ化された式の使用

OneToManyMapping mapping = new OneToManyMapping();
mapping.setAttributeName("policies");
mapping.setGetMethodName("getPolicies");
mapping.setSetMethodName("setPolicies");
mapping.setReferenceClass(Policy.class);

// Build a custom expression here rather than using the defaults
ExpressionBuilder policy = new ExpressionBuilder();
mapping.setSelectionCriteria(policy.getField("POLICY.SSN")).equal(policy.
  getParameter("HOLDER.SSN")));

110.3.2 ExpressionのメソッドgetField

ExpressionのメソッドgetFieldは、特定の名前のデータベース・フィールドを表す式を返します。このメソッドを使用すると、マッピングの選択基準を構成できます。引数は、必要なフィールドの完全修飾名です。フィールドは現在の問合せ全体に対して有効ではないため、このフィールドの取得元の表を表す式に、このメソッドを送信する必要があります。110.6項「データ問合せとデータ式」も参照してください。

例110-15は、ExpressionのメソッドgetFieldの使用方法を示します。

例110-15 ExpressionのメソッドgetParameterの使用

ExpressionBuilder address = new ExpressionBuilder();
Expression exp = address.getField("ADDRESS.EMP_ID").equal(
    address.getParameter("EMPLOYEE.EMP_ID")
);
exp = exp.and(address.getField("ADDRESS.TYPE").equal(null));

110.4 問合せキーと問合せ式

問合せキーとは、データベース・フィールド名の、スキーマ非依存の別名です。

問合せキーは、リレーショナル・データベース・プロジェクトでのみサポートされています。

問合せキーは、すべてのダイレクト・マッピングおよびリレーションシップ・マッピングで使用するために自動的に生成されます。問合せキーの名前は、クラス属性名です。

問合せキーの作成および変更方法の詳細は、119.10項「問合せキーの構成」を参照してください。

例110-16は、問合せキーfirstNameを、それに対応する直接にマップ済のEmployee属性に対して使用する方法を示します。

例110-16 自動生成された問合せキーの式での使用

Vector employees = session.readAllObjects(Employee.class,
  new ExpressionBuilder().get("firstName").equal("Bob"));

例110-17は、TopLinkの式フレームワーク内で1対1問合せキーを使用する方法を示します。

例110-17 式での1対1問合せキーの使用

ExpressionBuilder employee = new ExpressionBuilder();
Vector employees = session.readAllObjects(Employee.class,
  employee.get("address").get("city").equal("Ottawa"));

コレクション・リレーションシップでの個別の結合を定義する1対多問合せキーおよび多対多問合せキーにアクセスするには、ExpressionのメソッドanyOfを使用します。

110.5 複数の式

式では、副問合せ(SQLの副選択)とパラレル選択がサポートされます。副問合せを作成するには、式ビルダーを1つ使用します。パラレル選択の場合、単一の問合せを定義するときに式ビルダーを複数使用します。そうすることで、関連のないオブジェクトの結合をオブジェクト・レベルで指定できます。

110.5.1 副選択と副問合せの使用方法

一部の問合せでは、その中に含まれる他の問合せ(副問合せ)の結果が比較されます。SQLは、副選択によってこの比較をサポートします。TopLinkの式は、副選択をサポートする副問合せを提供します。

副問合せを使用すると、集計値(countsminmax)や関連のないオブジェクト(existsincomparisons)に対して問合せを行う複雑な式を定義できます。副問合せを取得するには、レポート問合せのインスタンスを任意の式比較操作に渡すか、式ビルダーでsubQuery操作を使用します。副問合せに親問合せと同じ参照クラスが指定されている必要はありません。副問合せ専用の式ビルダーを使用する必要があります。

副問合せはネストさせることも、並列に使用することもできます。副問合せでカスタムSQLを使用することも可能です。

単一の値を受け入れる式比較操作(equalgreaterThanlessThan)の場合は、副問合せの結果として単一の値が返される必要があります。値セットを受け入れる式比較操作(inexists)の場合は、副問合せの結果として値セットが返される必要があります。

例110-18は、部下が6人以上いるすべての従業員に一致する式を作成する方法を示します。

例110-18 比較およびカウント操作を使用した副問合せの式

ExpressionBuilder emp = new ExpressionBuilder();
ExpressionBuilder managedEmp = new ExpressionBuilder();
ReportQuery subQuery = new ReportQuery(Employee.class, managedEmp);
subQuery.addCount();
subQuery.setSelectionCriteria(managedEmp.get("manager") .equal(emp));
Expression exp = emp.subQuery(subQuery).greaterThan(5);

例110-19は、オタワ市で給与が最も高い従業員に一致する式を作成する方法を示します。

例110-19 比較および最大操作を使用した副問合せの式

ExpressionBuilder emp = new ExpressionBuilder();
ExpressionBuilder ottawaEmp = new ExpressionBuilder();
ReportQuery subQuery = new ReportQuery(Employee.class, ottawaEmp);
subQuery.addMax("salary");
subQuery.setSelectionCriteria(ottawaEmp.get("address").get("city").equal("Ottawa"));
Expression exp =   emp.get("salary").equal(subQuery).and(emp.get("address").get("city").equal("Ottawa"));

例110-20は、プロジェクトを持たないすべての従業員に一致する式を作成する方法を示します。

例110-20 notExists操作を使用した副問合せの式

ExpressionBuilder emp = new ExpressionBuilder();
ExpressionBuilder proj = new ExpressionBuilder();
ReportQuery subQuery = new ReportQuery(Project.class, proj);
subQuery.addAttribute("id");
subQuery.setSelectionCriteria(proj.equal(emp.anyOf("projects"));
Expression exp = emp.notExists(subQuery);

110.5.2 パラレル式の使用方法

パラレル式を使用すると、関連のないオブジェクトを比較できます。パラレル式には複数の式ビルダーが必要ですが、レポート問合せを使用する必要はありません。それぞれの式に専用の式ビルダーが必要です。さらに、classを引数としてとるコンストラクタを使用する必要があります。パラレル式のクラスは同一である必要はありません。また、1つの問合せの中に複数のパラレル式を作成できます。

複数の式ビルダーのうち1つのみが、その問合せのプライマリ式ビルダーとみなされます。このプライマリ・ビルダーは、ゼロ引数の式コンストラクタを使用します。このコンストラクタのクラスは問合せから取得されます。

例110-21は、性別の異なる他の従業員と同じ姓を持つすべての従業員と一致する式を作成する方法と、返される結果が配偶者である可能性を示します。

例110-21 2名の別々の従業員に関するパラレル式

ExpressionBuilder emp = new ExpressionBuilder();
ExpressionBuilder spouse = new ExpressionBuilder(Employee.class);
Expression exp = emp.get("lastName").equal(spouse.get("lastName"))
  .and(emp.get("gender").notEqual(spouse.get("gender"));

110.6 データ問合せとデータ式

式を使用して、オブジェクトではなくデータを取得できます。これは、外部キーやバージョン・フィールドなど、データベース内のマップされていない情報を扱う際の一般的な方法です。

通常、オブジェクトを問い合せる式ではオブジェクトの属性が参照されます。その結果、他のオブジェクトが参照される場合もあります。データ式では表とそのフィールドが参照されます。1つの問合せの中でデータ式とオブジェクト式を組み合せることができます。TopLinkは、データを問い合せる式で使用する主なメソッドとして、getFieldgetTableの2つを提供します。

110.6.1 getFieldメソッドの使用方法

getFieldメソッドを使用すると、オブジェクトのマップされていない表、またはマップされていないフィールドからデータを取得できます。どちらの場合も、フィールドはそのオブジェクトのクラスで表される表の一部である必要があります。表の一部でない場合は、問合せを実行したときに例外が発生します。

getFieldメソッドを使用して、オブジェクトの外部キー情報を取得することもできます。

例110-22は、オブジェクトに対してデータ式のメソッド(演算子)getFieldを使用する方法を示します。

例110-22 オブジェクトに対するgetFieldの使用

builder.getField("[FIELD_NAME]").greaterThan("[ARGUMENT]");

110.6.2 getTableメソッドの使用方法

getTableメソッドは、データベース内のマップされていない表を表す式を返します。この式は、getFieldメソッドを使用したときに、マップされていないフィールドを取得するためのコンテキストを提供します。

例110-23は、getFieldおよびgetTableを同一の式内で併用する方法を示します。

例110-23 getTableとgetFieldの併用

builder.getTable("[TABLE_NAME]").getField("[FIELD_NAME]").equal("[ARGUMENT]");

一般的に、getTableおよびgetFieldメソッドを使用するのは、多対多リレーションシップをサポートするリンク表(参照表)から情報を取得する場合です。

例110-24では、リンク表を使用する多対多リレーションシップを読み取り、リンク表の追加フィールドのチェックも行っています。このコードは、従業員のマネージャをデータ問合せの基礎として使用し、オブジェクト問合せとデータ問合せを組み合せたものです。プロジェクトIDのパラメータ化も使用しています。

例110-24 リンク表に対するデータ問合せの使用

ExpressionBuilder emp = new ExpressionBuilder();
Expression manager = emp.get("manager");
Expression linkTable = manager.getTable("PROJ_EMP");
Expression empToLink = emp.getField("EMPLOYEE   .EMP_ID").equal(linkTable.getField("PROJ_EMP.EMP_ID");
Expression projToLink = linkTable.getField("PROJ_EMP
  .PROJ_ID").equal(emp.getParameter("PROJECT.PROJ_ID"));
Expression extra = linkTable.getField("PROJ_EMP.TYPE").equal("W");
query.setSelectionCriteria((empToLink.and(projToLink)).and(extra));

110.7 式の作成

式は、Oracle JDeveloper、TopLink WorkbenchまたはJavaを使用して作成できます。

Oracle JDeveloperまたはTopLink Workbenchを使用すると、名前付き問合せで使用する基本的な式を作成できます(110.7.1項「TopLink Workbenchを使用した式の作成方法」を参照)。

Javaコードを使用すると、より複雑な式を作成し、Expression APIの機能を完全活用できます(110.7.2項「Javaを使用した式の作成方法」を参照)。

110.7.1 TopLink Workbenchを使用した式の作成方法

名前付き問合せ用にTopLinkの式を作成するには、次の手順を実行します。

  1. 名前付き問合せの形式タブの「編集」をクリックするか、問合せ文字列をダブルクリックします。「式ビルダー」ダイアログ・ボックスが表示されます。

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

    図110-1 「式ビルダー」ダイアログ・ボックス

    図110-1の説明が続きます
    「図110-1 「式ビルダー」ダイアログ・ボックス」の説明

    図110-1の数字の付いたコールアウトは、次のユーザー・インタフェース・コンポーネントを示します。

    1. 式ツリー

    2. 引数

  2. 「追加」または「ネストの追加」をクリックして、新規の式を作成します。TopLinkでは、各ノードとネストされたノードに順序番号を割り当てます。

    既存の式を削除する場合は、「削除」をクリックします。

  3. ノードを選択し、「論理演算子」リストを使用して、ノードの演算子(ANDORNot ANDまたはNot OR)を指定します。

次の表を使用して、各式の引数フィールドを指定します。

フィールド 説明
第1引数 「編集」をクリックし、第1引数の問合せキーを選択します。「問合せキーの選択」ダイアログ・ボックスが表示されます。

110.7.1.1項「引数の追加」に進みます。

演算子 TopLinkでの式の評価方法を指定します。有効な演算子には、Equal、Not Equal、Equal Ignore Case、Greater Than、Greater Than Equal、Less Than、Less Than Equal、Like、Not Like、Like Ignore Case、Is NullおよびNot Nullがあります。
第2引数 第2引数を指定します。
  • リテラルの場合: 「タイプ」を選択し、「値」にリテラル値を入力します。

  • 問合せキーの場合: 「編集」をクリックし、問合せキーを選択します。

  • パラメータの場合: 「追加」をクリックし、新しいパラメータを追加して、リストから選択します。

110.7.1.1項「引数の追加」に進みます。


「OK」をクリックします。TopLink Workbenchで、式が「名前付き問合せ」タブに追加されます。

110.7.1.1 引数の追加

各式には、評価する要素(引数)があります。Is NullまたはNot Null演算子を使用する式で必要な引数は、1つのみです。

新しい引数を追加するには、次の手順を実行します。

  1. 既存の式を選択するか、あるいは「追加」または「ネストの追加」をクリックして新規の式を名前付き問合せに追加します。

  2. 「第1引数」の場合は、「編集」をクリックします。「問合せキーの選択」ダイアログ・ボックスが表示されます。

    図110-2 問合せキーの選択

    図110-2の説明が続きます
    「図110-2 問合せキーの選択」の説明

  3. 属性を選択し、問合せでnull値を受け入れるかどうかを指定し、「OK」をクリックします。

    「NULLを許容」および「Noneを許容」オプションを使用すると、外部結合で使用する式を定義できます。

    「NULLを許容」オプションを選択すると、ExpressionBuilderのメソッドgetAllowingNullが使用されます。

    「Noneを許容」オプションを選択すると、ExpressionBuilderのメソッドanyOfAllowingNoneが使用されます。

    詳細は、110.2.7.2項「結合でのTopLink Expression APIの使用」を参照してください。

  4. 「演算子」リストを使用して、TopLinkでの式の評価方法を指定します。

  5. 「第2引数」の場合は、「リテラル」「問合せキー」または「パラメータ」を選択します。

    • 引数が「リテラル」の場合は、リテラルのタイプ(StringまたはIntegerなど)を選択し、リテラルの値を入力します。

    • 引数が「問合せキー」の場合は、「編集」をクリックします。「問合せキーの選択」ダイアログ・ボックスが表示されます(手順3および図110-2を参照)。

    • 引数が「パラメータ」の場合は、「追加」をクリックし、パラメータを追加してから、リストを使用してそのパラメータを選択します。

この手順を、各式またはネストした式について繰り返します。

例110-25 式のサンプル

後述の式では、次の条件に当てはまる従業員を検索します。

  • Jonesという姓のマネージャがいるか、マネージャがいません。

  • Betaという名前が付くプロジェクトかプロジェクトID 4に従事しています。

  • カナダ在住で給与が25,000を超えています。

    アメリカ在住で給与が37,500を超えています。

AND
  1.manager(Allows Null).lastName EQUAL "Jones"
  2.OR
    2.1.projects.name LIKE "BETA"
    2.2.projects.id EQUAL "4"
  3.OR
    3.1.AND
      3.1.1.address.country EQUAL "Canada"
      3.1.2.salary GREATER THAN "25000"
    3.2.AND
      3.1.1.address.country EQUAL "United States"
      3.1.2.salary GREATER THAN "37500"

110.7.2 Javaを使用した式の作成方法

Javaコードで式を作成するには、ExpressionクラスまたはExpressionBuilderのメソッドgetを使用します。

ExpressionBuilderは、問合せ対象のオブジェクトのかわりとなります。問合せを構成するには、オブジェクトの属性に対応するメソッドをExpressionBuilderに対してコールします。ExpressionBuilderオブジェクトには、問合せ対象のオブジェクトのタイプに応じた名前を付けることをお薦めします。


注意:

ExpressionBuilderのインスタンスは特定の問合せ専用です。既存のビルダーを使用して別の問合せを作成しようとしないでください。既存のビルダーには最初の問合せに関連した情報が残っているためです。

例110-26は、問合せキーlastNameを使用して、フィールド名L_NAMEを参照する方法を示します。

例110-26 ExpressionBuilderを使用した単純な式の作成

Expression expression = new ExpressionBuilder().get("lastName").equal("Young");

例110-27は、and論理演算子を使用して、小さな2つの式を組み合せることによって、複雑な式を作成する方法を示します。

例110-27 AND論理演算子を使用した2つの式の組合せ

ExpressionBuilder emp = new ExpressionBuilder();
    Expression exp1, exp2;
    exp1 = emp.get("firstName").equal("Ken");
    exp2 = emp.get("lastName").equal("Young");
    return exp1.and(exp2);

例110-28は、notLike演算子を使用して式を作成する方法を示します。

例110-28 式でのデータベース関数notLikeの使用

Expression expression = new ExpressionBuilder().get("lastName").notLike("%ung");

110.8 ユーザー定義関数の作成と使用

同じ関数の実装方法がデータベースによって異なることがあります。たとえば、データが昇順で返されることを指定する引数は、ASCまたはASCENDINGです。このような相違に対処するために、TopLinkではリレーショナル・データベースによって異なる関数やその他の演算子を認識できます。

TopLinkにはプラットフォーム固有の演算子のほとんどが用意されていますが、必要に応じて、独自の演算子を作成できます。

ユーザー定義関数を作成するには、ExpressionOperatorクラスを使用します。

ExpressionOperatorには、セレクタと文字列のVectorを指定します。

演算子が前置演算子と後置演算子のどちらであるかも指定できます。前置演算子の場合、最初の定数文字列が最初の引数の前に出力されます。後置演算子の場合は、最初の引数の後に出力されます。

ユーザー定義関数を作成する場所と、それをTopLinkの式フレームワークに追加する方法は、その新しい関数をすべてのデータベース・プラットフォームで利用するのか、特定のデータベース・プラットフォームでのみ利用するのかによって異なります。

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

110.8.1 特定のプラットフォームで利用可能なユーザー定義関数の作成方法

独自プラットフォームの特定の操作をオーバーライドする関数を作成するには、次の手順を実行します。

  1. 希望のDatabasePlatformoracle.toplink.platform.databaseまたはoracle.toplink.platform.database.oracleパッケージに含まれるもの)のサブクラスを作成します。DatabasePlatformには、protectedスーパークラス・メソッドaddOperatorをコールするpublicメソッドが用意されています。

    ...
    public class MyDatabasePlatform extends DatabasePlatform {
        protected void initializePlatformOperators() {
            super.initializePlatformOperators();
            // Create user-defined function
            ExpressionOperator toUpper = new ExpressionOperator();
            toUpper.setSelector(ExpressionOperator.ToUpperCase);
            Vector v = new Vector();
            v.addElement("UPPERCASE(");
            v.addElement(")");
            toUpper.printAs(v);
            toUpper.bePrefix();
            toUpper.setNodeClass(FunctionExpression.class);
    
            // Make it available to this platform only
            addOperator(toUpper);
        }
    }
    
  2. このプラットフォーム・サブクラスを使用するようにセッションを構成します(20.2項「プロジェクト・レベルでのリレーショナル・データベース・プラットフォームの構成」または98.2項「セッション・レベルでのリレーショナル・データベース・プラットフォームの構成」を参照)。

110.8.2 すべてのプラットフォームで利用可能なユーザー定義関数の作成方法

すべてのプラットフォームで利用可能な関数を作成するには、例110-29に示すように、ExpressionOperatorのメソッドaddOperatorを使用します。

例110-29 すべてのプラットフォームに対するtoUpper関数の追加

ExpressionOperator toUpper = new ExpressionOperator();
toUpper.setSelector(600);
Vector v = new Vector();
v.addElement("NUPPER(");
v.addElement(")");
toUpper.printAs(v);
toUpper.bePrefix();
toUpper.setNodeClass(FunctionExpression.class);

ExpressionOperator.addOperator(toUpper);

注意:

setSelectorメソッドの番号は、定数値で表します。この番号が500を超えていることを確認してください(500以下の番号はTopLinkで予約されています)。

110.8.2.1 ユーザー定義関数の使用

例110-30は、すべてか特定のいずれのプラットフォーム用に関数を追加するのかに関係なく、ExpressionのメソッドgetFunctionを使用して、定数値600で示されたユーザー定義式演算子にアクセスする方法を示します。

例110-30 ユーザー定義関数へのアクセス

ReadObjectQuery query = new ReadObjectQuery(Employee.class);
ExpressionBuilder builder = query.getExpressionBuilder();
Expression functionExpression = builder.get("firstName").
    getFunction(600).equal("BOB");
query.setSelectionCriteria(functionExpression);
session.executeQuery(query);