「SObject row was retrieved via SOQL without querying the requested field」エラーの原因と対処法


エラーの概要

SalesforceのApex開発で頻繁に遭遇する「SObject row was retrieved via SOQL without querying the requested field」エラーは、SOQLクエリで取得していないフィールドにアクセスしようとした際に発生します。このエラーを回避するためには、SOQLクエリの記述を適切に管理することが重要です。


エラーの原因

このエラーは以下のような状況で発生します:

  1. Apexコード
    • SOQLクエリに含まれていないフィールドを参照しようとした場合。
  2. Visualforceページ
    • 標準コントローラーで取得していないフィールドを参照しようとした場合。

エラーの解決方法

1. SOQLクエリの修正

不足しているフィールドをSOQLクエリに明示的に追加します。

エラー発生例:

// 必要なフィールド "Industry" を取得していない
List<Account> accList = [SELECT Id, Name FROM Account];
System.debug('Account industry is ' + accList[0].Industry); // エラー発生

修正例:

// 必要なフィールドをクエリに追加
List<Account> accList = [SELECT Id, Name, Industry FROM Account];
System.debug('Account industry is ' + accList[0].Industry); // 正常動作

2. Visualforceページの修正

方法1: カスタムコントローラーで不足フィールドをクエリする
カスタムコントローラーを使用し、必要なフィールドを含める。

例:

public class AccountController {
    public Account acc { get; set; }
    public AccountController() {
        acc = [SELECT Id, Name, Industry FROM Account WHERE Id = :ApexPages.currentPage().getParameters().get('id')];
    }
}

方法2: 隠れた参照を追加する
Visualforceページで隠れた参照を使用することで、必要なフィールドを取得します。

例:

<apex:outputText value="{!Condition__c.Criterion__c}" rendered="false"/>

3. 動的SOQLの使用

フィールドが動的に変化する場合や、使用されるフィールドが不明な場合には、動的SOQLを使用してすべてのフィールドを取得することも可能です。

例:

String objectName = 'Account';
SObjectType sobjectType = Schema.getGlobalDescribe().get(objectName);
List<String> fieldNames = new List<String>(sobjectType.getDescribe().fields.getMap().keySet());
String query = 'SELECT ' + String.join(fieldNames, ',') + ' FROM ' + objectName;
List<SObject> records = Database.query(query);
System.debug(records);

注意点

  1. トリガーでの発生

    • トリガーでも同様のエラーが発生する可能性があり、必要なフィールドを明示的にクエリすることが推奨されます。
  2. Salesforceのリリース影響

    • 一部のエラーはSalesforceのアップデートで挙動が変更される場合があるため、最新リリースノートを確認してください。

コメント