問合せヘルパー関数の使用方法
次のセクションでグローバル関数を定義した後、ビジネス・ロジックでは、SQL select文の構造を削除する構文を使用して、問合せタスクを簡単に実行できます。
たとえば、ジョブ・コードが営業担当であるStaffMember
ビジネス・オブジェクトの表からEメール、姓および名を問い合せるには、次のようなコードを記述できます:
def salesReps = adf.util.queryMaps(select: 'Email,LastName,FirstName',
from: 'StaffMember',
where: 'JobId = :JobCode',
orderBy: 'LastName,FirstName',
binds: [JobCode: 'SA_REP'])
select
およびfrom
の名前付きパラメータのみが必要です。 その他は、使用する必要がある場合にのみ指定します。 queryMaps()
関数は、Map
オブジェクトのList
を返します。各オブジェクトには、select
パラメータで指定したフィールドの値のみが含まれます。
queryMaps()
の「代わりに」で、次に示すようにqueryRows()
メソッドを使用します。 結果は、更新可能な属性を持つRow
オブジェクトのList
で、現在のトランザクション内の他の変更済オブジェクトとともに検証および保存されます。 結果はList
であるため、for
ループで直接使用できます。 また、コードがループ内で更新する予定であるselect
リストにSalary
列が含まれていることにも注意してください。 // Update the salary of sales reps to increase it by 5 percent
for (curRep in adf.util.queryRows(select: 'Salary',
from: 'StaffMember',
where: 'JobId = :JobCode',
binds: [JobCode: 'SA_REP'])) {
// Round the salary to two digits after increasing by 5%
curRep.Salary = (curRep.Salary * 1.05 as Double).round(2)
}
where
句で単一の行を識別する場合、または結果の最初の行のみを取得する場合は、コンパニオン単一行戻り関数を使用します:
-
Map queryMap(Map options)
- 最初の問合せ結果行がMap
として返されるか、行が戻されなかった場合はnull
が返されます -
Object queryRow(Map options)
- 最初の問合せ結果行を返すか、行が戻されなかった場合はnull
を返します
問合せによって返される行の合計数のみをコンピュートする場合は、queryCount()
関数を使用します。 ただし、単一行の存在をテストすることが目的の場合は、queryMap()
またはqueryRow()
を使用し、戻り値がnull
でないかどうかをテストする方が効率的であることに注意してください。
問合せメソッドでサポートされる名前付きパラメータの完全なリストは次のとおりです。 ビジネス・オブジェクト名およびフィールド名を示すすべての場所は、case-sensitiveです。
-
select
- ビジネス・オブジェクト・フィールド名のカンマ区切りリスト(String
、「必要な」) -
from
- ビジネス・オブジェクトの名前(String
、「必要な」) -
where
- ビュー基準フィルタ述語(オプションでバインド変数を参照するString
) -
orderBy
- フィールド名のカンマ区切りリスト(String
。オプションで、降順の場合は"desc
"のサフィクス) -
binds
-where
述語(Map
)で参照されるバインド変数名/値のペア -
ignoreNullBinds
- [Boolean
]がtrue
に設定され、nullバインド値を含むwhere
述語要素が無視されます
where
句では、変数によるユーザー定義に加えて、次の組込みバインド変数名を参照できます:
-
SysUser
- 現在ログインしているユーザーの名前、またはそれ以外の場合はanonymous
(String
) -
SysToday
- 現在の日付(Date
) -
SysNow
- 現在の日時(Datetime
)
たとえば、現在の日付の為替レートのリストを問合せするには、次のような問合せを作成します。 ユース・ケースでは単一の行を返す必要があり、データの変更を計画していないため、queryMap()
を使用して、コードで変換済通貨値のコンピュートに必要な単一のRate_c
属性を取得します。
def rate = adf.util.queryMap(
select: 'Rate_c',
from: 'ExchangeRate_c',
where: 'From_c = :Base and To_c = :Other and Date_c = :SysToday',
binds: [Base: 'GBP', Other: 'EUR'])
def convertedVal = sourceVal * rate.Rate_c
queryRows()
, queryMaps()
, queryRow()
, queryMap()
およびqueryCount()
は、実装で同じコアquery()
ヘルパー関数をコールします。 この機能により、次のことが集中化されます: select
およびfrom
必須オプションが存在することを検証していますfrom
パラメータで渡されたオブジェクト名を使用したnewView()
を使用したビュー・オブジェクトの作成select
リスト・フィールド名をトークン化し、selectAttributesBeforeQuery()
に渡すwhere
およびbinds
パラメータが指定されている場合のユーザー指定のバインド変数の定義where
パラメータが指定されている場合のビュー基準フィルタ式の適用- システム変数またはユーザー指定バインド変数(あるいはその両方)の値の設定
- ビュー・オブジェクトの返却
コードでバインド変数に対して異なる値を使用して同じ問合せを複数回再実行する必要がある場合は、ビュー・オブジェクトを返すコアquery()
関数を使用します。 結果を自分で反復し、適切なバインド変数を再割当てして、異なる複数のビュー・オブジェクトを作成せずにビュー・オブジェクトを再度実行できます。 この方法は、単一のトリガーまたはオブジェクト関数でビュー・オブジェクトが多すぎる場合の実行時例外を回避するために重要です。
queryMap()
関数を使用します。 このアプローチでは、ループの反復ごとに新しいビュー・オブジェクトが1つ作成されます。 反復される行数が予測できないほど大きい場合、この方法では、単一のトリガーまたは関数で作成できるビュー・オブジェクト数の上限に達したときに、ランタイム・リソース例外を生成できます。 // Will be updating the queried rows, so use queryRows()
for (txn in adf.util.queryRows(select:'Id,Cleared_c,Currency_c,Amount_c,Date_c',
from: 'Transaction_c',
where: "Cleared_c = 'N'")) {
def rate = 1
// If transaction currency is different than GBP, lookup historical
// exchange rate for the date of the transaction to convert the
// transaction currency into GBP
if (txn.Currency_c != 'GBP') {
// NOT BEST PRACTICE: Using a query inside a loop!
rate = adf.util.queryMap(
select: 'Rate_c',
from: 'ExchangeRate_c',
where: "From_c = :Base and To_c = 'GBP' and Date_c = :ForDate",
binds: [Base: txn.Currency_c, ForDate: txn.Date_c ])?.Rate_c
}
if (rate) {
txn.Cleared_c = 'Y'
// Multiply original txn amount by rate and round to 2 decimal places
txn.AmountInGBP_c = (txn.Amount_c * rate as Double).round(2)
}
}
query()
ヘルパー関数をコールすることをお薦めします。 ループ内で使用できるビュー・オブジェクトを返します。 ループの反復ごとに、バインド変数を適切な値に設定し、問合せを再実行します。 前述のルーチンのこのベスト・プラクティス・リライトを次に示します。 // BEST PRACTICE: Create a reusable query for looking up the exchange rate using
// ~~~~~~~~~~~~~ bind variable values of the correct datatype. Inside the loop
// set the correct bind var values and execute the same view object over & over
def rateVO = adf.util.query(
select: 'Rate_c',
from: 'ExchangeRate_c',
where: "From_c = :Base and To_c = 'GBP' and Date_c = :ForDate",
binds: [Base: 'XXX', ForDate: today() ])
// Will be updating the queried rows, so use queryRows()
for (txn in adf.util.queryRows(select:'Id,Cleared_c,Currency_c,Amount_c,Date_c',
from: 'Transaction_c',
where: "Cleared_c = 'N'")) {
def rate = 1
// If transaction currency is different than GBP, lookup historical
// exchange rate for the date of the transaction to convert the
// transaction currency into GBP
if (txn.Currency_c != 'GBP') {
// Set any bind variables to new values for current loop iteration
setBindVariable(rateVO,'Base',txn.Currency_c)
setBindVariable(rateVO,'ForDate',txn.Date_c)
// Execute the same view object with the new bind variable values
rateVO.executeQuery()
rate = rateVO.first()?.Rate_c
}
if (rate) {
txn.Cleared_c = 'Y'
// Multiply original txn amount by rate and round to 2 decimal places
txn.AmountInGBP_c = (txn.Amount_c * rate as Double).round(2)
}
}