実務でapexをみててレコードを1件だけ受け取りたいときにListを使用しているコードをみた
何故か気になったのでしらべた結果をまとめてみる
結論
- 単一sObject代入:0件だと
QueryException(List has no rows for assignment to SObject) - List代入:0件でも 空リスト(例外なし、
nullでもない)
詳しく
どうやら
Account a = [SELECT Id FROM Account WHERE Name = 'X' LIMIT 1];
のようにオブジェクトに代入しようとするコードがあり、結果が0件数だとQueryExceptionが発生して例外が投げられてしまう
しかし、
List rows = [SELECT Id FROM Account WHERE Name = 'X'];
// 0件 → rows.size() == 0、例外なし、rows自体はnullではない
のようにListで受け取るとExceptionにならず空リストが残るだけだかとなりからの場合にExceptionをなげず処理をおこないたい場合など柔軟に処理をかける
Listで受け取ってかつ0件の時にExceptionを投げたい場合
Listで受け取るが0件でExceptionを投げたい場合は以下のようにコードを記載することでExceptionを投げれる
List rows = [SELECT Id, Name FROM Account WHERE Name = :name LIMIT 1];
if (rows.isEmpty()) {
throw new AuraHandledException('Account not found');
}
Account a = rows[0];
しかし、システム例外にはnewを使えないものもあり、場合によってはExceptionを継承したクラスを自分で実装する必要がでてくる、、(例外クラスのテストクラスとかってどんな感じなんだろうか、、)
おまけ:SOQLで文字列を使うときの注意
必ずバインド変数を使い、文字列連結をしない
文字列連携を使ってクエリ文を作成してからSOQLを使用してもクエリ実行は可能だが、エスケープ漏れなどが発生しやすい
String idStr = /* 外部入力など */;
List rows = [SELECT Id FROM Account WHERE Id = :idStr]; // OK
// '… WHERE Id = \'' + idStr + '\'' ← NG(エスケープ漏れ・バグの温床)
null/空白を早期リターンで弾く
バインド変数をSOQLで使用する際はバインド変数のnullチェックを事前に行うことによって予期せぬ不具合を防ぐことができる
if (String.isBlank(idStr)) {
// 実行しない・return・適切な例外など
}
