function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
kobackykobacky 

数式項目が計算されるタイミングにつきまして

お世話になっております。

数式項目が計算されるタイミングについてご質問させて頂きます。
数式項目は、データベースからSelectされる時にのみ計算され、以後は再計算されないのでしょうか?

(数式項目はSOQLのSelect文で取得された後は、数値型と同じ扱いとなるのでしょうか?)

なお、これを検証するため、下記のような環境条件でコードを実行してみました。

■環境条件
カスタムオブジェクト(MathTest__c)を作成
  ・param__c(数値):数式のパラメータとして使用
  ・CalcResult__c(数式):「param__c * 2」

■コード(Visualforce)

<apex:page controller="MathTestController" >
	<apex:pageBlock >
		<apex:pageBlockSection id="refresh" >
			<apex:form >
				<apex:outputText value="{!MathTest.param__c}" />
				<apex:outputText value="{!MathTest.CalcResult__c}" />
				<apex:commandButton action="{!ChangeParam}" value="変数変更" rerender="refresh" />
				<apex:commandButton action="{!Save}" value="保存" />
				<apex:commandButton action="{!Cancel}" value="キャンセル" />
			</apex:form>
		</apex:pageBlockSection>
	</apex:pageBlock>
</apex:page>

 
■コード(コントローラ)

public with sharing class MathTestController {
	//オブジェクト
	private MathTest__c sobjMathTest = null;
	public MathTest__c MathTest{
		get
		{
			return sobjMathTest;
		}
	}
	
	//コンストラクタ
	public MathTestController(){
		//レコードを1件取得
		sobjMathTest = [select Id, param__c, CalcResult__c from MathTest__c limit 1];
	}
	
	//数式計算の元となる値をインクリメント
	public Pagereference ChangeParam(){
		sobjMathTest.param__c++;
		return null;
	}
	
    //保存する
    public PageReference Save() {
    	//DBのアップデート
    	update sobjMathTest;
    	//リファレンスの作成
    	Pagereference page = new Pagereference(System.currentPageReference().getUrl());
    	page.setRedirect(true);
    	//リファレンスの返却
        return page;
    }
    
    //キャンセルする
    public PageReference Cancel(){
    	//リファレンスの作成
    	Pagereference page = new Pagereference(System.currentPageReference().getUrl());
    	page.setRedirect(true);
    	//リファレンスの返却
        return page;
    }
	
}

 

このページを表示すると、(param__cの初期値が1の場合)param__cの値として1が、
CalcResult__cの値として2(1 × 2)が表示されます。

ここで「変数変更」ボタンを押下すると、ChangeParamメソッドが呼び出され、param__cが
1つインクリメントされます。さらに、「id="refresh"」を指定してrerendarをかけているので、
param__cに2、CalcResult__cに4が表示されることを期待しました。

しかし、実際の動作としてはparam__cに2が、CalcResult__cに2が表示されました。
このことから、数式の計算はデータベースからSelectで値を持ってきた時にのみ行なわれる
のだと考えたのですが、これは間違いないでしょうか?

ちなみに最終的に実現したいことのイメージは下記のような感じで、

その過程で数式に関する上記の疑問が生じました。
1.データベースからレコードを取得し、画面に描画する。
2.画面に描画されたコントロールに対してユーザーが様々な編集を行う。
3.rerendar属性を持つボタン動作(ajax)により、コントローラに保持する変数の値を変更する。

  (上記のテストコードにおいては、sobjMathTest)
4.ユーザーには編集内容に従って、画面が更新して表示される。
  (上記のテストコードにおいては、数式が再計算されて「4」と表示されて欲しい、など。)
5-1.ユーザーが保存ボタンを押すと、変更がDBに保存される。
5-2.ユーザーがキャンセルボタンを押すと、変更が破棄され、最初に画面を開いた状態に戻る。

 

 

なお、VisualforceやApexの経験が浅いということもあり、

上記のコードや、言っていることにおかしなことがあるかもしれません。

もし何かおかしなところがありましたら、ご指摘頂けると幸いです。

 

以上、よろしくお願い致します。

ikouikou

数式項目はDBに保存したタイミングで計算されます。

つまり画面側でいくらparam__cをインクリメントしても、数式であるCalcResult__cは何も変わりません。

インクリメントされたsobjMathTestをupdateして再取得すれば、カウントされた結果が返ってきます。

kobackykobacky

ikou様、ご回答ありがとうございます。

 

> 数式項目はDBに保存したタイミングで計算されます

 

取得するタイミングではなく、保存したタイミングでしょうか?
こちらにつきましては若干疑問なのですが、保存したタイミングでのみ計算されるとすると、
例えばNOW関数を用いる(レコード取得時の日時を必要とする)数式の計算に不都合がある気がします。

 

・・などと考えて調べていたら、下記の記事を見つけました。
http://itpro.nikkeibp.co.jp/article/COLUMN/20110722/362726/
(「数式項目は、利用時に再計算されます。」とありました。レコードの取得時にも再計算されるようです。)

 


> つまり画面側でいくらparam__cをインクリメントしても、数式であるCalcResult__cは何も変わりません。
> インクリメントされたsobjMathTestをupdateして再取得すれば、カウントされた結果が返ってきます。

 

質問が説明不足で大変申し訳なかったのですが、下記を両立させたいと考えております。
・「保存」ボタンを押下した段階でDBの更新を確定する。
  →「変数変更」ボタン(インクリメントするボタン)を押下した段階ではupdateを行いたくない。
・「変数変更」ボタンの押下により「sobjMathTest.param__cのインクリメント」と
 「sobjMathTest.CalcResult__c(数式項目)の再計算、表示更新」を行う。

 

これを両立するためには、更新が確定されていないsobjMathTest.param__c値を用いて
(update、再selectせずに)数式項目を再計算する必要があると思いますが、
そのような方法はありますでしょうか?

 

(結局、上記のような方法はないのではないかと思い、数式項目を使うのではなく、
 MathTest__cのラッパークラスを作ってそこに計算式を持たせるといった方法を取ろうとしていますが。。)

 

重ねての質問になってしまい恐縮ですが、よろしくお願い致します。

ikouikou

>(「数式項目は、利用時に再計算されます。」とありました。レコードの取得時にも再計算されるようです。)

 

なるほど、よく考えてみればその通りですね。

 

数式の項目自体はDB側に値を保持するフィールドを持っているわけではなく、数式の計算式しか持っていないので

その式の計算元となるparam__cの値をupdateせずに数式の値を変えることはできませんね。

もちろん数式の値をController側に取得しておき、DB側の値を変えるのではなく、Controller側でインクリメントボタン押下時に計算することは可能かもしれませんが。