ビューステートを意識したVisualforce【セールスフォース】


こんにちは、アンダーソンです。
今回は上級デベロッパーの勉強中に気になったシリーズです。
ビューステートにも制限があるようで、上級デベロッパーともなると、
そのあたりのことも頭に入れた設計をしていく必要があるようです。
今回はビューステートに関して考察していきます。



<!-- /wp:separator -->

ビューステートの制限

そもそもビューステートとはなんなのでしょうか。
Visualforceでカスタムコントローラを呼び出す際に表示させるバインドされた変数だ何だことだと認識しています。
※もっといい説明あったら教えてください。

てなことで、画面に表示できる情報は無限ではなく、135KBの制限を設けているわけですね。
これもガバナ制限みたいなものなので覚えてしまいましょう。
で、もし制限を超えてしまったらどうなるのか。

Visualforceはもちろんエラーで返されますし、VF側のエラーなのでApex側で例外をキャッチするなどは
当然できません。
かなりの曲者と言えるでしょう。

ビューステートを確認

今回、取引先責任者を単純に1000件表示させる画面を作ってみました。
表示させるのは名前のみです。
まずは普通にやってみた際のビューステートのサイズをみてみます。

Visualforce
<apex:page controller="sample" action="{!sample}">
    <apex:form >
        <apex:repeat value="{!conList}" var="con">
            <apex:inputField value="{!con.LastName}"/>
        </apex:repeat>
    <apex:form/>
<apex:page/>

Apex
public class sample {
    public List conList {get; set;}

    public void sample(){
        conList = [SELECT Id,LastName FROM Contact LIMIT 1000];
    }
}

かなり簡易的ですがこれを実行してみます。

conListのサイズは7.22KBとなっています。Internalというのも同じくらいサイズがありますが、
これはSalesforce側内部のステートで開発者側ではどうすることもできないようです。

ビューステートの最適化

ビューステートを軽減するためにはどうするのがいいのでしょうか。
そこで下記の方法をとるのがベストプラクティスとのことです。

  • 状態の維持に不可欠ではなく、ページの更新時にも不要な変数には、Apex コントローラで transient キーワードを使用する。
  • ビューステートの大部分をコントローラまたはコントローラ拡張で使用されているオブジェクトから取得していることが分かった場合は、Visualforce ページに関連するデータのみを戻すように SOQL コールの絞り込みを検討する。
  • ビューステートが大規模なコンポーネントツリーの影響を受けている場合は、ページが依存しているコンポーネント数の削減を試みる。
    引用:ビューステートの最適化

①そもそものコンポーネント数を考えなさいよ〜。
②SOQLを見直して適切なデータだけ戻そうね。
③特段状態維持しなくていいならtransientを使用しようね。

というものです。
①はいわずもがな表示の見直しをすればいいのですが、
②はコントローラで取得するSOQLそのものを見直すべきかもしれません。
例えば、先ほどのコントローラでContactオブジェクトの全ての項目をSELECTしてみます。
すると一気にビューステートでのサイズが増えます。

SOQLで無駄な項目の取得は避けましょうということですね。
そして③はそもそもビューステートから無くしちゃおうという作戦です。

先ほどのコードのApex側を書き換えます。

transient public List conList {get; set;}

これだけです。宣言の際にtransientを最初につけます。
すると同じページなのに、

この違いです。29.31KBあったのが8.08まで削減されました。

デメリット

transientにもデメリットがあります。
ページの更新時に不要な変数につけておかないと何かしらのアクションでページの変更が加わったりすると
無かったことになるので注意が必要です。
transientがある変数は状態の変更などには使えないため、あくまでも大量データを表示させる
output用の変数と頭に入れておくのがいいと思います。