はじめに
みなさまこんにちは。
SalesforceのSpring'21が2021年2月14日にメジャーリリースされましたね。
みなさまから見て「おっ、これは!」というような機能追加はありましたでしょうか。
気になった機能は人によって違うかと思いますが、私はSOQLのFIELDS()関数が目に留まったので、今回はこちらについて仕様や制約、その制約に対するちょっとしたTipsをご紹介したいと思います。
FIELDS()関数とは?
まずは簡単にFIELDS()関数の特徴を説明します。
Q.どこで使える?
A.SOQLの中でのみ使えます。
Q.何ができる関数?
A.簡単に言うとSQLの「*(アスタリスク)」と同じ役割です。
項目を1つ1つ指定せずともバリエーション(下記参照)に応じたすべての項目が取得できます。
Q.バリエーションは何がある?
A.以下の3種類があります。
- FIELDS(ALL) - すべての項目を抽出
- FIELDS(CUSTOM) - すべてのカスタム項目を抽出
- FIELDS(STANDARD) - すべての標準項目を抽出
Q.本当に全項目を取得できる?
A.厳密に言うと取得できない項目が生じるケースが1つだけあります。
クエリ実行ユーザの参照権限に基づいて項目が取得される仕様なので、参照権限がない項目は取得されません。
いかがでしょうか。
今まではSOQLで大量の項目をSELECTする際に煩わしさを感じていた人も多いのではないかと思いますが、FIELDS()関数はそんな悩みを解決してくれる関数のように見えますね。
FIELDS()関数の使い方
それでは、まず以下のFIELDS(STANDARD)を使ったクエリを開発者コンソールのQuery Editorから実行して、取引先のレコード全件と標準項目をすべて取得してみましょう。
SELECT FIELDS(STANDARD) FROM Account
その結果がこちらです。
取引先は標準項目が多いのでカラムがかなり狭くなっていますが、FIELDS(STANDARD)と書いただけで標準項目がSELECTできているのが分かります。
また、FIELDS(STANDARD)とFIELDS(CUSTOM)は通常の項目指定と組み合わせることも可能です。
例えば以下のように、FIELDS(CUSTOM)と標準項目をいくつか指定をしたクエリを実行してみます。
また、FIELDS(STANDARD)とFIELDS(CUSTOM)は通常の項目指定と組み合わせることも可能です。
例えば以下のように、FIELDS(CUSTOM)と標準項目をいくつか指定をしたクエリを実行してみます。
SELECT Name, Id, Phone, FIELDS(CUSTOM) FROM Account LIMIT 200
こちらが実行結果ですが、期待通りカスタム項目群に加えてName、Id、Phone項目が取得できていますね。
ちなみに、ここには例は示しませんが、サブクエリ内でもFIELDS()関数は使用することができます。
ちなみに、ここには例は示しませんが、サブクエリ内でもFIELDS()関数は使用することができます。
FIELDS()関数の制約とは
さて、気になった人もいるかと思いますが、先程のFIELDS(CUSTOM)と標準項目指定を組み合わせたクエリは、「LIMIT 200」をつけて実行しました。
これは何も気まぐれで付けた訳ではありません。実はここに、FIELDS()関数の制約が絡んでいるのです。
その制約とは、FIELDS(ALL)とFIELDS(CUSTOM)にはLIMITを必ず200以下で設定しなければならないというものです。
物は試しなので、先程のクエリから「LIMIT 200」を外して実行してみましょう。
SELECT Name, Id, Phone, FIELDS(CUSTOM) FROM Account
「The SOQL FIELDS function must have a LIMIT of at most 200」というエラーが発生してしまいました。
要するに「SOQL文に200件までのLIMITを付けて下さい」と言われています。やはりLIMITは200以下で指定しないとダメみたいですね。
この制限の背景として、カスタム項目はオブジェクトの制限内であればユーザが自由に作成できるため、クエリコストの予測が難しいという事情があるようです。
ちなみにFIELDS(STANDARD)にはLIMITの制限はありません。
理由として、標準項目は元々クエリのパフォーマンスやレスポンスサイズを考慮して設定されているからだそうです。
また、このカスタム項目と標準項目の違いによるFIELDS()関数の大きな制約はもう1つあります。
それは何かと言うと、FIELDS(ALL)とFIELDS(CUSTOM)はApexとBulk APIでは使用できないということです。
試しに、Query Editorではなく「open execute anonymous window」で匿名Apexコード内にSOQLを書いて実行してみます。
要するに「SOQL文に200件までのLIMITを付けて下さい」と言われています。やはりLIMITは200以下で指定しないとダメみたいですね。
この制限の背景として、カスタム項目はオブジェクトの制限内であればユーザが自由に作成できるため、クエリコストの予測が難しいという事情があるようです。
ちなみにFIELDS(STANDARD)にはLIMITの制限はありません。
理由として、標準項目は元々クエリのパフォーマンスやレスポンスサイズを考慮して設定されているからだそうです。
また、このカスタム項目と標準項目の違いによるFIELDS()関数の大きな制約はもう1つあります。
それは何かと言うと、FIELDS(ALL)とFIELDS(CUSTOM)はApexとBulk APIでは使用できないということです。
試しに、Query Editorではなく「open execute anonymous window」で匿名Apexコード内にSOQLを書いて実行してみます。
実行結果はこうなります。
「The SOQL FIELDS function is not supported with an unbounded set of fields in this API. 」というエラーが発生し、このAPIではFIELDS()関数はサポートされていないという趣旨のメッセージが書かれています。
ここまでをご覧いただくと、FIELDS(STANDARD)とFIELDS(ALL)・FIELDS(CUSTOM)には使用感に差があることがお分かりいただけたと思いますので、各シチュエーションにおけるFIELDS()関数の対応状況を簡単にまとめておきます。
「The SOQL FIELDS function is not supported with an unbounded set of fields in this API. 」というエラーが発生し、このAPIではFIELDS()関数はサポートされていないという趣旨のメッセージが書かれています。
ここまでをご覧いただくと、FIELDS(STANDARD)とFIELDS(ALL)・FIELDS(CUSTOM)には使用感に差があることがお分かりいただけたと思いますので、各シチュエーションにおけるFIELDS()関数の対応状況を簡単にまとめておきます。
FIELDS(STANDARD) | FIELDS(ALL),FIELDS(CUSTOM) | |
---|---|---|
Apex | 対応 | 非対応 |
Salesforce CLI | 対応 | LIMITを200以下に指定すれば対応 |
Bulk API 2.0 | 対応 | 非対応 |
REST API | 対応 | LIMITを200以下に指定すれば対応 |
SOAP API | 対応 | LIMITを200以下に指定すれば対応 |
Tips:Apex内のクエリで全項目SELECTするには?
さてここまでで、FIELDS(CUSTOM)とFIELDS(ALL)はApexで使用できないことが分かりました。ただそうは言っても、この記事を読んでいる開発者の方の中には「どうしてもApexでカスタム項目をすべてSELECTしたい!」というケースに遭遇する方もいるでしょう。
(実際に私も遭遇したことがあります。
そんな時にわざわざ項目をすべてSELECT句に書き連ねるのは手間ですし、コードの可読性も良くありません。
そこで、FIELDS(CUSTOM)を使わずにカスタム項目をすべて取得するコードをご紹介します。
public with sharing class GetAllFieldsUtil { // 引数にはカスタム項目を取得したいオブジェクト名を渡す public String getAllCustomFields(String objName) { String customQuery = ''; String delimiter = ', '; Schema.SObjectType objType = Schema.getGlobalDescribe().get(objName); // ここで指定したオブジェクトの項目定義を取得 Map<String, sObjectField> fieldsMap = objType.getDescribe().fields.getMap(); for (String fieldName : fieldsMap.keySet()) { // カスタム項目のみクエリになる文字列に追加 if (fieldName.endsWith('__c')) { customQuery += delimiter + fieldName; } } System.debug('query = ' + customQuery); return customQuery; } }
GetAllFieldsUtil.cls
public with sharing class SearchOpportunity { public void getOpportunityRecord() { List<Opportunity> oppList = new List<Opportunity>(); // Utilクラスをインスタンス化 GetAllFieldsUtil util = new GetAllFieldsUtil(); // クエリを実行 oppList = Database.query( 'SELECT FIELDS(STANDARD) ' + util.getAllCustomFields('Opportunity') + ' FROM Opportunity' ); } }
SearchOpportunity.cls
1つ目のGetAllFieldsUtilクラスのgetAllCustomFieldsメソッドの引数に、カスタム項目を取得したいオブジェクト名をString型で渡してあげるというのが使い方です。
これを行うと、対象オブジェクトのカスタム項目がすべて羅列されたクエリ用の文字列がreturnされてくる仕組みになっています。
(汎用的に使えるようにUtilクラスとしています。)
実際に使う際には2つ目のSearchOpportunityクラスのような形で呼び出してもらうと良いかと思います。
ちなみにこのクエリではFIELDS(STANDARD)も組み合わせています。
こうすることでFIELDS(STANDARD)で標準項目を、getAllCustomFieldsメソッドでカスタム項目をそれぞれ全SELECTしているため、事実上FIELDS(ALL)の挙動を実現しています。
クエリパフォーマンス的には負荷がかかりやすい手法なのでむやみに使うのは厳禁ですが、使い所を考えれば便利にお使い頂けると思います。
おわりに
以上FIELDS()関数についてご紹介してきましたが、いかがでしたでしょうか。
FIELDS()関数は確かに便利ではありますが、その反面まだ制約も多いのが現状です。
とはいえ、通常の項目指定と組み合わせる等、使い方を工夫したり場面を選べば有用な関数であることは間違いありません。上手く活用してみなさまがより良いSalesforceエンジニアライフを送っていただければ幸いです。
参考
Spring '21リリース注目の新機能~開発者向け~30 件