動的 SOQL

動的 SOQL は、Apex コードを使用して、実行時に SOQL 文字列の作成を参照します。動的 SOQL によって、さらに柔軟なアプリケーションの作成が可能になります。たとえば、エンドユーザーの入力に基づいた検索を作成したり、さまざまな項目名のレコードを更新したりできます。

実行時に動的 SOQL クエリを作成するには、次のいずれかの方法で Database.query または Database.queryWithBinds メソッドを使用します。

  • クエリが 1 つのレコードを返すときに、1 つの sObject を返します。
    sObject s = Database.query(string);
  • クエリが複数のレコードを返すときに、sObject のリストを返します。
    List<sObject> sobjList = Database.query(string);
  • バインド変数の対応付けを使用して sObject のリストを返します。
    List<sObject> sobjList = Database.queryWithBinds(string, bindVariablesMap, accessLevel);

通常の割り当てステートメントや for ループなど、インライン SOQL クエリが使用可能な場合はいつでも、Database.query および Database.queryWithBinds メソッドを使用できます。結果は、静的 SOQL クエリの処理とほぼ同様の方法で処理されます。

API バージョン 55.0 以降では、ユーザーモードでのデータベース操作機能の一部として、accessLevel パラメーターを使用してユーザーモードまたはシステムモードでクエリ操作を実行します。accessLevel パラメーターは、メソッドをシステムモードで実行するか (AccessLevel.SYSTEM_MODE)、ユーザーモードで実行するか (AccessLevel.USER_MODE) を指定します。システムモードでは、現在のユーザーのオブジェクト権限と項目レベル権限が無視され、クラスの sharing キーワードでレコード共有ルールが制御されます。ユーザーモードでは、現在のユーザーのオブジェクト権限、項目レベルのセキュリティ、および共有ルールが適用されます。デフォルトはシステムモードです。

動的 SOQL 結果は、Account や MyCustomObject__c、または汎用 sObject データ型などのように、具体的な sObject として指定できます。実行時に、システムは、クエリのタイプが宣言された変数の型と一致しているかどうか検証します。クエリが正しい sObject データ型を返さない場合、ランタイムエラーが発生します。したがって、汎用 sObject から具体的な sObject を割り当てる必要はありません。

動的 SOQL クエリには、静的クエリと同じガバナ制限があります。ガバナ制限についての詳細は、「実行ガバナと制限」を参照してください。

SOQL クエリの構文の詳細は、『SOQL および SOSL リファレンス』の「Salesforce Object Query Language (SOQL)」を参照してください。

動的 SOQL に関する考慮事項

Database.query を使用するときは、動的 SOQL クエリ文字列で単純なバインド変数を使用できます。クエリ内のバインド変数は、データベース操作の範囲内である必要があります。次の例は許可されます。
String myTestString = 'TestName';
List<sObject> sobjList = Database.query('SELECT Id FROM MyCustomObject__c WHERE Name = :myTestString');
ただし、インライン SOQL とは異なり、Database.query を使用するクエリ文字列では、バインド変数項目を使用できません。次の例はサポートされず、「Variable does not exist」というエラーになります。
MyCustomObject__c myVariable = new MyCustomObject__c(field1__c ='TestField');
List<sObject> sobjList = Database.query('SELECT Id FROM MyCustomObject__c WHERE field1__c = :myVariable.field1__c');
代わりに、次のように変数項目を文字列に解決し、その文字列を動的 SOQL クエリで使用できます。
String resolvedField1 = myVariable.field1__c;
List<sObject> sobjList = Database.query('SELECT Id FROM MyCustomObject__c WHERE field1__c =  :resolvedField1');

(API バージョン 57.0 以降) 別のオプションで Database.queryWithBinds メソッドが使用されます。このメソッドでは、クエリのバインド変数が Apex コード変数からではなく、Map パラメーターからキーを使用して直接解決されます。このため、クエリの実行時に変数が範囲内に含まれている必要がなくなります。次の例は、取引先名にバインド変数を使用する SOQL クエリを示しています。その値は acctBinds Map を使用して渡されます。

Map<String, Object> acctBinds = new Map<String, Object>{'acctName' => 'Acme Corporation'};

List<Account> accts = 
    Database.queryWithBinds('SELECT Id FROM Account WHERE Name = :acctName',
                            acctBinds, 
                            AccessLevel.USER_MODE);

SOQL インジェクション

SOQL インジェクションとは、ユーザーが SOQL ステートメントをあなたのコードに渡すことで、あなたのアプリケーションで意図していなかったデータベースメソッドを実行する手法です。動的 SOQL ステートメントを構築するためにアプリケーションがエンドユーザー入力に依存し、入力が適切に処理されなかった場合、常に Apex コードで発生する可能性があります。

SOQL インジェクションを防ぐには、escapeSingleQuotes メソッドを使用します。このメソッドは、ユーザーから渡される文字列のすべての単一引用符にエスケープ文字 (\) を追加します。このメソッドにより、すべての単一引用符を、データベースコマンドではなく、囲まれた文字列として処理します。

その他の Dynamic SOQL メソッド

このトピックの Dynamic SOQL の例は、Database.query メソッドと Database.queryWithBinds メソッドの使用方法を示しています。Dynamic SOQL は、次のメソッドでも使用されます。

  • Database.countQuery および Database.countQueryWithBinds: 実行時に動的 SOQL クエリが返すレコード数を返します。
  • Database.getQueryLocator および Database.getQueryLocatorWithBinds: Apex または Visualforce の一括処理で使用される QueryLocator オブジェクトを作成します。