Loading

SOQL クエリと条件ベースの共有に関する考慮事項

公開日: Oct 13, 2022
説明

※この記事は英語版を翻訳しており、一部機械翻訳を含むため内容は後日更新される可能性があります。最新の内容は英語版を参照してください。表示言語は画面右下の言語名から切り替えられます。

「with sharing」として宣言された Apex クラスが、トランザクションのコンテキストで SOQL クエリを実行し、条件ベースの共有ルールが実行中のユーザーと一部の行を共有する必要がある場合、クエリはこれらの行を取得できません。
これは、コミットフェーズ (Apex トランザクションが終了した直後) で、その行へのアクセスを提供する共有がデータベースに書き込まれるためです。

解決策

トリガーと実行の順序に従い、条件ベースの共有ルールは実行フローの最後で評価され、この時点でメモリに作成された共有はコミットフェーズで保存されます。Salesforce 要求の「コミット」は、レスポンスがユーザーに送信される直前に行われ、要求に対するすべての Apex 実行が終了したに行われます。

その結果、Apexトランザクションはコミット済みデータにアクセスできないため、 SOQL クエリは同じトランザクションで評価された条件ベースの共有ルールによって共有された行を返しません。これは、Apex トランザクションはコミットされたデータにアクセスできないためです。

回避策:

  • Apex コントローラーの修飾子を「without sharing」に変更することを検討します。
  • 条件ベースの共有ルールが評価されるトランザクションとは別のトランザクションで、必要な SOQL クエリを呼び出します。


サンプルシナリオ:

これは以下のステップで再現できます。

a) 以下の Apex コントローラー、Visualforce ページ、Apex トリガーを作成します。

public with sharing class AccountQueryIssue {
    public String debugString { get; set; }
    private Account a, b;    
    
    public AccountQueryIssue() {
        debugString = '';
    }
    
    public void createAccount() {
        // レコードタイプ ID を取引先のレコードタイプ ID に置き換え
        a = new Account(Name = 'Acme '+ System.now(), recordTypeId='012410000002S6O');
        insert a;
        debugString += '<br/>Inserted account:<br/>' + JSON.serialize(a) + '<br/>';

        try {
            b = [SELECT Id, Name, Owner.Alias FROM Account where id = :a.Id];
        } catch(Exception e) { }
        
        if(b != null)
            debugString += '<br/>Queried account:<br/>' + JSON.serialize(b) + '<br/>';
        else
            debugString += '<br/>Could not query account<br/>';
    }
}

VF Page

<apex:page controller="AccountQueryIssue" showHeader="false" sidebar="false">
    <apex:form >
        <apex:commandButton action="{!createAccount}" value="Create Account"/>
    </apex:form>
    <apex:outputText escape="false" value="{!debugString}"/>
</apex:page>

Apex トリガ

trigger ChangeOwner on Account (before insert) {
    for(Account a : Trigger.new) {
        // OwnerId を CEO ロールを持つユーザーの ID に置き換え
        a.OwnerId = '00541000000HJYT';
    }
}


b) Apex コントローラーで取引先の作成に使用したレコードタイプである取引先レコードを、CEO より下のロールを持つユーザーと共有する基準ベースの共有ルールを作成します。

c) CEO より下のロールを持つユーザーとしてログインし、上記の Visualforce ページに移動して [Create Account (取引先の作成)] をクリックします。「Could not query account」と表示されます。ただし、実行中のユーザーは、https://<instance>.salesforce.com/<accountId> にアクセスしてアカウントに移動できます。

ナレッジ記事番号

000382331

 
読み込み中
Salesforce Help | Article