6

Let's say we have an apex:commandButton, with immediate="false", and no apex:actionSupport. It's just a standard apex:commandButton inside an apex:form.

Additionally, suppose it has a reRender attribute which rerenders some form elements.

This page leaves out an important detail:

Order of Execution for Visualforce Page Postback Requests

Namely, when the various form elements are rerendered, you may imagine that some of them will call methods on the controller. For example, there may be some methods called to retrieve Boolean values to control the "rendered" attribute of certain elements. Additionally, elements such as apex:selectOptions may call methods on the controller to retrieve List<T> for their "value" attribute.

Is there any defined order for these method calls, or is it non-deterministic?

Here is one of my use cases where this is important. I have an apex:selectOptions which calls a controller action in its "value" attribute. Let's call this action "getOptions()". This must be run at postback time, as its contents are sensitive to certain controller member variables that are assigned by input elements during the postback. Also, I have some sections on the page that either render, or do not, depending upon whether "getOptions()" contains any data.

It would be ideal not to have to make 2 SOQL queries, one for the List and the other to retrieve a COUNT() aggregate, using the same predicate, but I can't see another option, since getOptions() may not have been called by the time the other element needs to know how many options were returned. It seems I need another method, getOptionCount() in order to be guaranteed to get the count.

1 Answer 1

5

You can't depend on the order of setters or getters. You should avoid doing this at all cost. In fact, you can't even guarantee that your setters or getters will be called only once per transaction, so your "two queries" might very well become four or six (or more!), depending on page structure.

If you must use this design, then opt for "lazy initialization", like so:

transient SObject[] records { get; set; }

void loadRecords() {
    if(records == null) {
        records = [select ... from ... where ...];
    }
}
public SObject[] getOptions() {
    loadRecords();
    // Do something with records
    return someArray;
}
public Integer getOptionsCount() {
    loadRecords();
    return records.size();
}

This makes sure your query is ran only once per transaction without regards to how many times your getters might be called. If view state size unimportant, you can simply assign the value during your action methods whenever they need to be updated. The bulk of any rendering you do should be within constructors or action methods, not getters or setters.

14
  • Thanks. I figured, based on absence of a definitive statement to the contrary, that there was no guarantee of order or number of executions. I like the tactic of delegating to loadRecords(), however I have cases where getOptionCount() may be called independently (minor rerender), and it will be more efficient to have a separate SOQL call which merely uses the COUNT() aggregate instead of mapping the entire dataset into memory via an SObject[] array or List<SObject>. Commented Jun 9, 2015 at 13:40
  • As an aside, for other readers, getOptionCount() is a better MVC pattern than other things I have seen, such as public void showThisSection{}, etc., as those patterns are putting view logic in the controller. Commented Jun 9, 2015 at 13:57
  • By the way, why editorialize about getters/setters, as my post did not reference getters/setters, and specifically referenced method calls? Just curious. Commented Jun 9, 2015 at 14:06
  • @PittsburghDBA getX and setX methods are also getters and setters, simply in a different form. The inline/default model provides a backing variable automatically and thus produces a different syntax from the function model, but this difference in syntax only surfaces in Apex Code-- as far as Visualforce is concerned, either model of getters and setters are acceptable.
    – sfdcfox
    Commented Jun 9, 2015 at 15:47
  • OK, so that's just platform voodoo, or sytactic sugar. For example, I named that getOptionCount() because I'm a long-time developer "out in the world". A real property accessor (AKA "gettor") would look like this: public Integer optionCount{ get { return this.optionCount; } } Commented Jun 9, 2015 at 17:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .