Print this page

Auto Number Field Issue

Knowledge Article Number 000182151
Description Changing the Auto Number Field to another datatype if it is referenced in Apex code throws the following error:

Validation Errors While Saving Record(s) There were custom validation error(s) encountered while saving the affected record(s). The first validation error encountered was "Cannot change field type of a custom field referenced in Apex class or trigger: AutoNumberTestMsg".

Generally, this type of issues occurs when there is a data migration to a new org. If there is an Auto Number field and it is referenced in triggers and apex code. However, to load this field one needs to change the type to text load it and then change it back. However, the apex code will prevent from changing the datatype. 
 
Some of the trickiest Force.com deployment problems that customer faces which involves custom fields of type Auto Number. Values in these fields cannot be updated without first temporarily changing their type to Text — but if the field is referenced in any Apex code, then the type cannot be changed at all!
However, it is possible through dynamic SOQL and the get() and put() methods.
Resolution
To illustrate the technique, create a custom object AutoNumberTest__c with which to experiment. The object should have a single custom field called “autonumber__c” of type Auto Number. After creating the object, you can experiment to prove that the type of the Autonumber__c field can be freely changed from Auto Number to Text and back to Auto Number again, allowing for necessary updates as part of conversion or recoveries. As a side note, this does not apply to the standard Name field set as auto number. Name fields are treated differently than custom fields, and the auto number attribute of the name field can be changed without running afoul of the Apex compiler’s type checking. Now, let’s write a trigger after insert or update of an AutoNumberTest__c object that references the autonumber__c column. The following example code uses the field to create a Note object and attach it to the AutoNumberTest__c object.
 
trigger AutoNumberTestMsg
      on AutoNumberTest__c (after insert, after update) {

  List newNotes = new List();

  for (AutoNumberTest__c a : Trigger.new ) {

    Note msg = new Note(
      parentId = a.id,
      title = '' + a.autonumber__c,
      body = '' + a
    );
    newNotes.add(msg);
  }
  insert newNotes;
}
 
This code iterates through all the new values in the trigger batch, creates a new Note object containing a string representation of the AutoNumberTest__c object, and, after looping through all the objects, inserts the new notes in a single DML statement. (The expression '' + a.autonumber__c returns a string representation of the value autonumber__c field.) After creating this trigger, attempting to change the column type from Auto Number causes the following error:
 
Validation Errors While Saving Record(s)
There were custom validation error(s) encountered
while saving the affected record(s). The first validation
error encountered was "Cannot change field type of a
custom field referenced in Apex class or trigger:
AutoNumberTestMsg".
 
In this particular example, it would be quite easy to comment out the existing code, change the field type to perform maintenance on data values, and then uncomment the code. It’s seldom easy and sometimes nearly impossible when promotion is involved or when the dependent code is more complicated.
The Winter ’09 introduction of the Object.get() and Object.put() methods provides a new alternative. We can change the expression a.autonumber__c to g.get('autonumber__c') and escape the compiler!
The new trigger is as follows:
 
trigger AutoNumberTestMsg
      on AutoNumberTest__c (after insert, after update) {

  List newNotes = new List();

  for (AutoNumberTest__c a : Trigger.new ) {

    Note msg = new Note(
      parentId = a.id,
      title = '' + a.get('autonumber__c'),
      body = '' + a
    );
    newNotes.add(msg);
  }
  insert newNotes;
}
 
It is now possible to change the type of the autonumber__c column without generating an error.
Of course, this change exposes us to a new class of run-time errors that otherwise would have been prevented by the compiler. For example, if we now change the API name of the autonumber__c field without also changing the trigger, the code will cause a run-time exception.
In more realistic scenarios, the changes required are usually more complicated and involve more significant risks of run-time problems.
For example, if we use a SOQL expression such as:
List aList =
    [select id, autonumber__c from AutoNumberTest__c];
 
We’ll encounter the same compiler-enforced restriction on changing the type of the autonumber field. We need to resort to dynamic SOQL and the Database.query() method to avoid the direct compiler reference to the field.
 
List aList =
    Database.query('select id, autonumber__c from AutoNumberTest__c');
 
Switching to dynamic soql queries can be unwieldy and could also be more difficult to maintain. (With the Spring ’09 release, we gain the ability to use ‘:’ interpolation in dynamic SOQL, which will make things a little easier.) However, in cases involving the need to temporarily change an Auto Number field to allow for updates, switching to dynamic SOQL will be far, far easier than some of the horrendous contortions that have been required in the past!




promote demote