Visualforceページから@ReadOnlyメソッドを実行する

今回の記事では、Apexを参照のみモードで動作させる@ReadOnlyアノテーションとその実行方法についてご紹介します。

Apexの「参照のみモート?」

SOQLクエリ実行時は、通常カ?ハ?ナ制限により1トランザクションで取得できるレコード件数に上限が設けられています。(Winter'14時点では50,000件) Apexを参照のみモート?で実行することで、このガバナ制限が緩和され最大1,000,000件のレコードが取得可能になります。

なお、参照のみモードにおいてはDML操作は一切不可となります。

参照のみモート?で実行する方法

方法1:Visualfocreの<apex:page>タグに readOnly="true" を指定する

<apex:page readOnly="true">

ページからコールされるすべてのメソッドが、参照のみモードで動作します。 この方法では、<apex:repeat>などの繰り返しコンポーネントで使用できるコレクションのサイズの上限が10,000(通常時は1,000)に緩和される効果もあります。

・Visualforce
・Apex

方法2:Apexメソッドに@ReadOnlyアノテーションを付加する

@ReadOnlyアノテーションを付加するためには以下の条件があります。

  1. global、またはpublicであること
  2. staticであること
  3. Webserviceとして定義すること、または@RemoteActionアノテーションを併せて付加すること

メソッドの例:

@ReadOnly webservice static void myMethod() {} @ReadOnly @RemoteAction public static void myMethod() {}

今回のサンプルでは、Webserviceとして定義したメソッドをVisualforceページ上のボタンから実行します。 50,001件のレコードをインポートして動作を確認してみます。

・Apex
・Visualforce

デバッグログの出力結果から50001件取得できたことが確認できます。

Number of query rows: 50001 out of 1000000

Webserviceメソッド使用時の注意事項

Apexコード開発者ガイドには、@ReadOnlyアノテーションについて以下の記述があります。

Visualforce ページでは@ReadOnlyアノテーションを使用してコントローラメソッドをコールすることができます。また、それらのメソッドは同じ制限が緩和された状態で実行されます。

しかし実際には、Webserviceメソッドはボタンのactionからも実行は可能ですがactionからの実行時は@ReadOnlyが無効になる点に注意が必要です。 以下のコードでは、ガバナ制限超過エラーが発生してしまいます。

実行結果:

System.LimitException: Too many query rows: 50001

これは、@ReadOnlyはWebserviceとしてコールしないと有効にならないというルールがあり、通常のガバナ制限が適用されたためです。

(参考:ReadOnly Annotation - Force.com Apex Code Developer's Guide

実装前に注意すること

大容量データを扱う処理の実装は、Apexガバナ制限の問題をクリアすればOKというわけではありません。処理のタイムアウトなど、その他のエラーについても考慮することが重要です。 実装時に陥りやすい点については、弊社今岡によるVisualforceでCSV...ちょっとハマったことにて詳しく紹介されておりますので是非ご覧下さい。 機能を有効に活用するためにも、検証は十分に行いましょう。