Friday, December 28, 2012

Using standard controller's "getRecord" method

There seems to be a common problem using the getRecord function, so I am going to write it down here.  This problem has haunted me a few times now.

Whenever you use a controller extension, extending a standard object, you can use the getRecord() to get the reference to the record.  For example, if you have an extension to the contact object, this can be what your Apex class looks like:

public class ContactExtension
{
    private Contact contact;

    public ContactExtension(ApexPages.StandardController sController)
    {
        this.contact = (Contact)sController.getRecord();
    }
}

Besides the obvious constructor, you will most likely have some other methods inside your class to manipulate the contact.  Let's say you want to provide a form so the user can change email address and phone number of the contact.  Your VisualForce class looks very simple

<apex:page standardController="Contact" extensions="ContactExtension">
    {!greeting}
    <apex:form>
        <apex:inputField value="{!contact.Email" />
        <apex:inputField value="{!contact.MobilePhone}" />
        <apex:commandButton action="{!save}" value="Save" />
    </apex:form>
</apex:page>

The {!greeting} is going to display some greeting messages.  That means we will need to write a getGreeting() method in the class.

If this is the definition of your getGreeting() inside the class,

public String getGreeting()
{
    return 'Hi ' + contact.FirstName + ' how have you been?  Please update the following.';
}

you will then get an error message that looks like this:

System.SObjectException: SObject row was retrieved via SOQL without querying the requested field: Contact.FirstName

Most of us think that as soon as we call the getRecord() method, then the entire record is loaded into the contact variable.  However if you have an object with 5000 fields, and you only need to use 2 or 3 in your Visualforce pages, do you think it really makes sense to load all 5000 fields for that record into the contact variable?  Probably not.

Then what can you do?  The easiest way is to do add this into your Visualforce page:
<apex:outputText value="{!contact.FirstName}"/>

If you say, but I don't want to display the contact name twice!  Then you can simply change this to:
<apex:outputText value="{!contact.FirstName}" rendered="false" />

By adding rendered="false", that will hide this variable.  Or perhaps use <apex:variable> instead, such as:
<apex:variable value="{!contact.FirstName}" var="contactFName" />

When you load this Visualforce page, the standard controller will scan through your Visualforce page and knows that you need this field, and when making the getRecord() method call, it automatically and implicitly adds this FirstName field into the SOQL.

Remember, if you want to use any field in your extension via the getRecord() method, you need to let it be known by making sure that the field exists in your Visualforce page!

(Another alternative is to write your own SOQL in your Apex class, but why make an extra SOQL call when you can avoid it?)

16 comments:

  1. You can use the below code when the controller variable is a ApexPages.StandardController before you call getRecord.

    controller.addFields(new List{'FirstName'});

    James Kent
    http://www.blueengine.com.au

    ReplyDelete
  2. Super helpful, exactly what I needed. The comment about addFields was great too, except it left out "", as in:

    controller.addFields(new List{'FirstName'});

    ReplyDelete
    Replies
    1. Oh, i see this site's comments nix anything in angle brackets. So, after List should be "String" inside of angle brackets. Meaning in the below example, replace String in square brackets with String in angle brackets:

      stdController.addFields(new List[String]{'FirstName'});

      Delete
  3. Thanks!!! Saved my time

    ReplyDelete
  4. I simply wanted to thank you so much again. I am not sure the things that I might have gone through without the type of hints revealed by you regarding that situation.
    java training in chennai

    ReplyDelete
  5. Appreciating the persistence you put into your blog and detailed information you provide.
    Best selenium training Institute in chennai

    ReplyDelete
  6. The young boys ended up stimulated to read through them and now have unquestionably been having fun with these things.

    Hadoop Training in Chennai

    ReplyDelete
  7. Your good knowledge and kindness in playing with all the pieces were very useful. I don’t know what I would have done if I had not encountered such a step like this.


    Devops Training in pune

    Devops Training in Chennai

    Devops Training in Bangalore

    AWS Training in chennai

    AWS Training in bangalore

    ReplyDelete
  8. After reading this web site I am very satisfied simply because this site is providing comprehensive knowledge for you to audience. Thank you to the perform as well as discuss anything incredibly important in my opinion. We loose time waiting for your next article writing in addition to I beg one to get back to pay a visit to our website in
    python training in tambaram
    python training in annanagar
    python training in OMR
    python training in chennai

    ReplyDelete
  9. I am sure this post has helped me save many hours of browsing other related posts just to find what I was looking for. Many thanks!
    Data Science course in kalyan nagar | Data Science course in OMR
    Data Science course in chennai | Data science course in velachery
    Data science course in jaya nagar

    ReplyDelete
  10. Hiiii....Thanks for sharing Great information...Nice post...Keep move on...
    Salesforce Training in Hyderabad

    ReplyDelete

Please leave a comment.