Apexクラス内では、『with sharing』を宣言することで実行ユーザのアクセス権限のある情報のみ取得するように制御できます。システム権限で実行する場合は『without sharing』と宣言します。
複数のクラスを使用する処理で『with sharing』と『without sharing』がそれぞれ宣言された場合の挙動について確認してみます。
はじめに
検証用にName項目のみのカスタムオブジェクトを作成しました。
共有設定で非公開(private)に設定しています。これでwith sharingのときは他のユーザのレコードを取得できないようになります。
Administratorというユーザでレコードを5件作成しました。作成者であるAdministratorは検索ページでこのレコードを表示できます。
この条件でAdministratorとは別のユーザが検索処理を行う形で検証を進めていきます。
検証①:with sharing
まずはwith sharingを宣言したクラスでクエリを実行した場合です。
結果は次の通り、Administratorとは別のユーザが検索した場合、Administratorの作成したレコードは検索結果には表示されません。
検証②:without sharing
それではwith sharingをwithout sharingに変更して実行してみます。
Administratorが作成したレコードも取得できるようになりました。
ここまでは大丈夫ですね。それではクエリ実行のみ行うDaoクラスを用意してwith sharingとwithout sharingがそれぞれ宣言された場合を確認していきます。
検証③:with sharing → without sharing
まず、クエリを実行するDaoクラスを用意します。こちらはwithout sharingで宣言します。
Controller側ではwith sharingを宣言します。
これで元のクラスはwith sharing、クエリ実行クラスはwithout sharingという形になりました。この状態で実行してみた結果がこちらです。
クエリ実行を行ったクラスの権限が優先されることを確認できました。
検証④:without sharing → with sharing
さてそれでは、検証③の条件とは逆にクエリ実行を行うクラスの方をwith sharingに変更して確認してみます。
まずDaoクラスはこんな感じです。
Controller側はwithout sharingを宣言します。
クエリ実行クラスの権限が優先されるはずなのでwith sharingで実行されるはずです。結果はこちら。
予定どおりですね。このようにwith sharing / without sharingの宣言はクエリ実行を行うクラスの宣言が適用されます。
最後にもう1つのパターンを確認してみたいと思います。上の検証では、Daoクラスはstaticを宣言して呼び出しました。そうではなく、newを宣言してインスタンスを生成して呼び出した場合を確認してみます。
検証⑤:Daoクラスがstaticでない場合
Daoクラス側です。without sharingを宣言します。
Controller側です。with sharingを宣言します。
クエリ実行するクラスの宣言が適用されるはずなのでwithout sharingで実行されるはず・・。
結果です。
without sharingの権限で実行できていますね。これでクエリ実行クラスの呼び出しは、staticでもnewのときでも違いがないことが確認できました。
複数クラスでの『with sharing』と『without sharing』の切り替えはこのように適用されます。基本的には『with sharing』を宣言しておくことになると思います。例外時、例えばApexトリガーで件数の集計処理を行うようなときは、without sharingを宣言して組織内のすべてのレコードにアクセスさせる..というような使い分けを行う感じだと思います。