June 4, 2013

Adding new fields can break existing visualforce pages

I recently came across an interesting discussion where adding new field to a Object broke some of existing code. It’s strange right, mostly removing or renaming fields is risky, as they could break some String expressions or merge fields.

Here is the error in one of the possible form for “Name” field

Unknown property 'VisualforceArrayList.Name'
Error is in expression '{!Contact.Location__r.Name}' in component <apex:page> in page abhinav:contactss

Here is one quick way to end up in this problem:

For keeping stuff simple, I have tried to keep the fixture minimal.

  1. Lets assume we have an custom object called “Location__c”
  2. Create a lookup field on standard Contact object, it will relate with “Location” custom object and field API name is “Location”
  3. Here is a simple Visualforce page which uses this field, which works fine till now.
    <apex:page standardController="Contact" >
    
      {!Contact.Location__r.Name}
    
    </apex:page>
    
    
  4. Now add a lookup field on Location object, which relates to Contact. Make sure the “Child relationship name” is “Location” not “Locations”, as indicated below Contact lookup relationship fields
  5. Now revisit the same Visualforce page, you will get the error this timeUnknown property 'VisualforceArrayList.Name' error in Visualforce page

 

Why this happened ?

Contact is having two relations now with same name i.e.

  1. One “Location__r” which refers to the parent Location record i.e. Location__c record.
  2. Second “Location__r” which refers to child relationship location records i.e. List of Location__c records.

This breaks the Visualforce runtime, as the above code maps code is actually meant to load parent location’s name from Contact, but it gets an handle to child relationship one i.e. “List of Location__c records”. So as indicated in error, there is no such property called “Name” in ArrayList and it fails at runtime.

 

Important observations

  1. This problem only comes in Visualforce code referring an ambiguous relationship, similar Apex code will work fine, one such sample is shown below
    public static Contact loadLastChangedContact () {
            Contact con = [Select Name, Location__r.Name from Contact Order By LastModifiedDate DESC LIMIT 1]; 
            System.debug ('Location Name: ' + con.Location__r.Name);
            return con;
        }
    
    
  2. Above case applies to Formulas as well, they are not affected by ambiguous fields.
  3. This problem could be trapped, if the Visualforce page is saved again, after adding new field. It gives the same compilation error.
  4. This error will not be trapped in “Run All Tests” as its not related to Apex, but Visualforce runtime. Even if your test cases are using System.Test.setCurrentPage(‘…’), they will not be able to trap this runtime failure. So, be careful when adding fields to existing objects, its pretty common to see new fields being added to objects, without full testing of existing code.
  5. The same problem could come on renaming the fields, which leads to this duplicity in relationship names on single object.

Credits

Credit goes to Rajendra Ogra for bringing up this discussion and sharing his findings.