Thursday, December 30, 2010

Error: Invalid field for SObject when building a table in a Visualforce page

Error: Invalid field for SObject when building a table in a Visualforce page

This is a small error but for a newbie it can take lot of time in undertanding it and solving it so just thought to share it.

There is a tutorial in VF guide which works very fine.
It uses standard objects Accounts and Contacts

<apex:page standardController="Account">
<apex:pageBlock title="Hello {!$User.FirstName}!">
You are viewing the {!} account.
<apex:pageBlock title="Contacts">
<apex:pageBlockTable value="{!account.Contacts}" var="contact">
<apex:column value="{!contact.Name}"/>
<apex:column value="{!contact.MailingCity}"/>
<apex:column value="{!contact.Phone}"/>

Now if we want to do the same thing for two custom objects say obj1__c and obj2__c
generally one would use

<apex:page standardController="obj1__c">
<apex:pageBlock title="Hello {!$User.FirstName}!">
<apex:pageBlockTable value="{!obj1__c.obj2__c}" var="o">
<apex:column value="{!o.Name}"/>
<apex:column value="{!o.fieldName}"/>

this will give error Invalid field obj2__c for SObject obj1__c

This happens because child name is not referenced properly

Salesforce generates a child relationship name that can be referenced in the page. For Account to Contact it is Contacts. Salesforce asks for a relationship name when creating the lookup relationship or master detail relationship.
Relationship name can be checked in Salesforce Schema in Eclipse. Go to the parent Object, drill down to the child relationships and find the relationship name.

so by referencing obj1__c.obj2__r (at line 5 i.e. pageblock table value) the error can be solved.
<apex:pageBlockTable value="{!obj1__c.obj2__r}" var="o">

Wednesday, December 29, 2010

Savepoint, rollback and viewstate

I just came to know about how view state affects the buddies savepoint and rollback so just wanted to share about it.

Every time a page is called, it goes through a particular set of actions. One entire set of actions is a single transaction. When you view the page, Salesforce goes through a series of actions, which generally looks like the following:

1) Load the appropriate classes into memory, initialize memory heap, use an implied Database.setSavePoint().

2) If the View State is empty (i.e. you are visiting the page the first time), call the page's constructor methods.

3) If View State is not empty, load those memory variables into the object (deserialization).

4) If View State is not empty, call each of the Setter methods for all values that were rendered into the form from the last action.

5) If an "action" was called, perform the action.

6) Call the getter methods and render the page's output.

7) Set the view state for the form and output the total results (Serialization).

8) Call the implied Database.commit() if nothing went wrong in any prior step.

(These may not be precise order). A transaction is started before each page action, and completed at the end of each action.

Every time you call back to the server, it is one complete transaction. For example, if you press a "Next" button, then press a "Save" button, even though you're on the same page, with the same view state throughout, you've had three distinct database transactions (the initial load, the Next action, and the Save action). You can't roll back changes between each transaction, because the transaction is already complete.

This is the same inherent design with every major RDBMS out there on the market-- when one whole transaction is done, the data is committed. In every major database out there, each page served results in one entire transaction.

While View State can hold almost any data, the database can't place the transaction in a holding pattern indefinitely. It must immediately commit or rollback the entire transaction before the end of a single transaction unit, and the default is to commit unless there is an uncaught exception or error that causes it to rollback automatically, or the programmer manually rolls back a transaction.

While using savePoint and Rollback make sure that you are using it in same view state or else savepoint will change to null and it will give argument passed cannot be null at line database.commit().