データ構造から SQL ステートメントへの値の受け渡し

pureQuery には、SQL ステートメントにおいてパラメーターの値としてアノテーション付きメソッドまたはインライン・メソッドに受け渡す際のパラメーターの使用に関するデフォルトの規則があります。また pureQuery には、OUT パラメーターおよび INOUT パラメーターの登録時に渡されるパラメーターの使用法についてのデフォルトの規則もあります。アノテーション付きメソッドを使用する場合、ParameterHandler<T> インターフェースのインプリメンテーションによって、こうしたデフォルトの規則をオーバーライドできます。

ParameterHandler<T> インターフェースにあるメソッドは、handleParameters() だけです。pureQuery がこのメソッドを呼び出すと、アノテーション付きメソッドに渡されたパラメーターと一緒に、SQL ステートメントの実行に使用された PreparedStatement オブジェクトを渡します。

ParameterHandler<T> オブジェクトを使用して、SQL ステートメントにおけるパラメーターの値を設定し、任意の OUT パラメーターまたは INOUT パラメーターを登録します。 java.sql.PreparedStatement インターフェースについては、ご使用の Java SDK の Javadoc を参照してください。

例 1

この例の目的については、コード内のコメントで説明されています。

package com.samplePackage;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;

import com.ibm.pdq.runtime.generator.ParameterHandler;

// これはカスタム ParameterHandler の例です。この例では、
// メソッド・パラメーターをステートメント・パラメーターとして設定する前に、
// (1) メソッド・パラメーターを検証し、
// (2) メソッド・パラメーターを処理します。// また、このカスタム ParameterHandler は、
// (3) ステートメント・パラメーターの 1 つにハードコーディング値を設定します。
//
// 最初のステートメント・パラメーターは bonusFactor です。// 設定値は、1 から 2 までの間の数値です。
// メソッド・パラメーターとして渡される値は、100% から 200% までの値です。
// そのため、パラメーター・ハンドラーは、渡された値が
// 100 から 200 までの値であることを検証し、100 で値を除算してから、
// その値をステートメント・パラメーター bonusFactor として設定します。
//
// 2 番目のステートメント・パラメーターは bonusMaxSumForDept です。これは、
// パラメーター・ハンドラーでハードコーディングされた値 ($20,000.00) に設定されます。
public class BonusIncreaseParameterHandler implements ParameterHandler
{
  // ?1 が戻り値です。
  // IN パラメーター ?2 は、渡されたメソッド・パラメーター newBonusPercentageOfOldBonus から設定されます。
  // IN パラメーター ?3 は、ParameterHandler の固定数値から設定されます。
  // この SQL の CALL ステートメントには OUT パラメーターが以下のように 4 つあります。
  // (1) ?4 => deptsWithoutNewBonuses
  // (2) ?5 => countDeptsViewed
  // (3) ?6 => countDeptsBonusChanged
  // (5) ?7 => errorMsg
  public void handleParameters (PreparedStatement stmt, Object... parameters) throws SQLException
  {
    CallableStatement cstmt = (CallableStatement) stmt;
    
    double newBonusPercentageOfOldBonus = (Double) parameters[1];

    // パラメーターの値が妥当であることを検証します。
    if (100 > newBonusPercentageOfOldBonus || 200 < newBonusPercentageOfOldBonus) { throw new RuntimeException (
      "The bonusFactorPercentage must be between 100 and 200 inclusive.  The new bonus will be this percentage of the old bonus.  (So, for example, if bonusFactorPercentage=100, then the bonus will not change.)"); }

    // cstmt に設定する bonusFactor を計算します。
    double bonusFactor = newBonusPercentageOfOldBonus / 100.0;
    
    // この cstmt パラメーターは固定値です。
    double bonusMaxSumForDept = 20000.00;
    
    // OUT パラメーターを登録し、IN パラメーターを設定します。
    cstmt.registerOutParameter (1, Types.INTEGER);
    stmt.setDouble (2, bonusFactor);
    stmt.setDouble (3, bonusMaxSumForDept);
    cstmt.registerOutParameter (4, Types.VARCHAR);
    cstmt.registerOutParameter (5, Types.INTEGER);
    cstmt.registerOutParameter (6, Types.INTEGER);
    cstmt.registerOutParameter (7, Types.VARCHAR);
  }

}

例 2

この例の目的については、コード内のコメントで説明されています。

package com.samplePackage;

import java.sql.PreparedStatement;
import java.sql.SQLException;

import com.ibm.pdq.runtime.generator.ParameterHandler;

// これは、「レガシー」ユーザー Bean を未変更のまま使用できるようにする、
// カスタム ParameterHandler の例です。Bean インプリメンテーションについて、および
// 未変更のまま使用する理由について詳しくは、CustomDepartment クラスを参照してください。
public class CustomDepartmentParameterHandler implements ParameterHandler
{

  public void handleParameters (PreparedStatement stmt, Object... parameters) throws SQLException
  {
    CustomDepartment department = (CustomDepartment) parameters[0];
    stmt.setString (1, department.getDepartmentCode ()); 
  }

}

以下に、CustomDepartment Bean の定義を記します。

package com.samplePackage;

// これは、理論上のユーザーが変更を加えない可能性のある「レガシー」Bean の例です。
// 変更を加える必要がある場合には、以下の Bean に対応するようにしてください。
// (1) プロパティー名を変更する、@Column を追加する、または @ColumnOverride を追加する、
// このいずれかを行い、プロパティーを列にマップできるようにします。
// (2) 組み込まれている getter に対応する setter を追加します。
//
// 変更 (1) は簡単な修正です。ただし、ユーザーが以下のようにたくさんの Bean
// を持っているか、変更できないレガシー・コードがある場合には、
// 代わりに ParameterHandler を使用できます。
//
// 変更 (2) の場合には、ユーザーの設計アーキテクチャーにかなりの変更が求められる
// 可能性があります。例えば、このようなケースでは、departmentName と departmentCode の
// 両方が一緒に変更される場合にのみ、ユーザーがこれらに対する変更を許可することが
// あります。そのために、changeDepartment(String,String) メソッドはありますが、
// setDepartmentName(String) メソッドまたは setDepartmentCode(String) メソッドはありません。
// カスタム ParameterHandler では、ユーザーはこの Bean を現状のまま使用することができます。
public class CustomDepartment
{
  private String departmentName;
  private String departmentCode;
  // 他のプロパティー

  public CustomDepartment (String departmentName, String departmentCode)
  {
    this.departmentName = departmentName;
    this.departmentCode = departmentCode;
  }
  
  public void changeDepartment (String departmentName, String departmentCode)
  {
    this.departmentName = departmentName;
    this.departmentCode = departmentCode;
  }

  public String getDepartmentName ()
  {
    return departmentName;
  }

  public String getDepartmentCode ()
  {
    return departmentCode;
  }

  // 他のメソッド
}

例 3

この例の目的については、コード内のコメントで説明されています。

package com.samplePackage;

import java.sql.PreparedStatement;
import java.sql.SQLException;

import com.ibm.pdq.runtime.generator.ParameterHandler;

// これは、メソッド・パラメーターにおいて既に使用可能な値に基づいて SQL パラメーターが
// 設定されているのではないカスタム・パラメーター・ハンドラーの例です。この場合、
// プロジェクト長は ProjectLevel パラメーターのプロパティー値に AdefUser パラメーターの
// プロパティー値を乗算して求められます。
public class ProjectLevelParameterHandler implements ParameterHandler
{
  public void handleParameters (PreparedStatement stmt, Object... parameters) throws SQLException
  {
    System.out.println("CDS in parameter handler");
    ProjectLevel projectLevel = (ProjectLevel) parameters[0];
    AdefUser adefUser = (AdefUser) parameters[1];
    
    int numberOfEmployees = adefUser.getNumberOfEmloyees ();
    double lengthInDays = projectLevel.getMinimumProjectLengthInDaysPerDepartmentMember () * numberOfEmployees;
    String workDepartment = adefUser.getWorkDept ();
    
    System.out.println("CDS trying to set parameters");
    stmt.setDouble (1, numberOfEmployees);
    stmt.setDouble (2, lengthInDays);
    stmt.setString (3, workDepartment);
  }
}

以下に、AdefUser Bean の定義を記します。

package com.samplePackage;

import com.ibm.pdq.annotation.Column;

public class AdefUser
{
  private String workDept;
  private int numberOfEmloyees;
  
  public AdefUser (String workDept, int numberOfEmployees)
  {
    this.workDept = workDept;
    this.numberOfEmloyees = numberOfEmployees;
  }
  
  @Column(name="no_of_employees")
  public int getNumberOfEmloyees ()
  {
    return numberOfEmloyees;
  }
  
  public void setNumberOfEmloyees (int numberOfEmloyees)
  {
    this.numberOfEmloyees = numberOfEmloyees;
  }
  
  public String getWorkDept ()
  {
    return workDept;
  }
  
  public void setWorkDept (String workDept)
  {
    this.workDept = workDept;
  }
}

以下に、ProjectLevel Bean の定義を記します。

package com.samplePackage;


public class ProjectLevel
{
  private int projectLevel;
  private double minimumProjectLengthInDaysPerDepartmentMember;
  
  public ProjectLevel(int projectLevel, double minimumProjectLengthInDaysPerDepartmentMember)
  {
    this.projectLevel = projectLevel;
    this.minimumProjectLengthInDaysPerDepartmentMember = minimumProjectLengthInDaysPerDepartmentMember;
  }

  public double getMinimumProjectLengthInDaysPerDepartmentMember ()
  {
    return minimumProjectLengthInDaysPerDepartmentMember;
  }

  public void setMinimumProjectLengthInDaysPerDepartmentMember (double minimumProjectLengthInDaysPerDepartmentMember)
  {
    this.minimumProjectLengthInDaysPerDepartmentMember = minimumProjectLengthInDaysPerDepartmentMember;
  }

  public int getProjectLevel ()
  {
    return projectLevel;
  }

  public void setProjectLevel (int projectLevel)
  {
    this.projectLevel = projectLevel;
  }

}

フィードバック