この記事について
Apexの動的SOQLのバインド変数では、通常の静的SOQLのバインド変数と異なる仕様があったため記録する。
オブジェクトのプロパティは使用できない
例えば以下のacc.Id
のような、オブジェクトのプロパティを参照するバインド変数だと例外が発生する。
※Apexクラスのインスタンスのプロパティも同様
Account acc = new Account(Name = 'ABC株式会社');
insert acc;
String query = 'SELECT Id FROM Account WHERE Id = :acc.Id'; // "acc.Id"はダメ
List<Account> accounts = Database.query(query); // ここで例外発生:System.QueryException: Variable does not exist: acc.Id
この問題を回避するには、オブジェクトのプロパティを参照しなければよいので、プリミティブ型の変数を作成して使用するとよい。
Account acc = new Account(Name = 'ABC株式会社');
insert acc;
Id accountId = acc.Id; // プリミティブ型の変数を作成し "acc.Id" を代入
String query = 'SELECT Id FROM Account WHERE Id = :accountId'; // オブジェクトのプロパティを参照しないため例外が発生しない
List<Account> accounts = Database.query(query);
Database.query
メソッドの実行時点のスコープ内にある変数名である必要がある。
動的SOQLだとしばしば別のメソッドやQueryBuilder
などのカスタムApexクラスを用いてSOQLを作成することがあるが、バインド変数がDatabase.query
メソッドを実行する際のスコープ内に存在している必要がある。
例えば、以下のような動的SOQLクエリを作成するbuildQuery
メソッドがあったとする。
public class SampleQueryBuilder {
public static String buildQuery(String accountId) {
return 'SELECT Id FROM Account WHERE Id = :accountId';
}
}
このメソッドを使用して以下のようなコードを実行した場合、accountId
という変数がDatabase.query
メソッド実行時のスコープ内に存在しないため、例外が発生する。
Account acc = new Account(Name = 'ABC株式会社');
insert acc;
String query = SampleQueryBuilder.buildQuery(acc.Id);
List<Account> accounts = Database.query(query); // ここで例外発生:System.QueryException: Variable does not exist: accountId
この問題を回避するには、バインド変数で使用する変数をDatabase.query
メソッド実行時のスコープ内(Database.query
メソッドを呼び出しているメソッド内)に作成する必要がある。
Account acc = new Account(Name = 'ABC株式会社');
insert acc;
String query = SampleQueryBuilder.buildQuery(acc.Id);
Id accountId = acc.Id; // スコープ内に"accountId"がある状態。クエリの実行時にこの変数が使用される
List<Account> accounts = Database.query(query);