The Secret Life of an SObject: Defaults

Default values, dirty field tracking, checkboxes / booleans, and the Winter’13 loadDefaults argument…

When creating custom objects, we can define default values for our fields which are automatically applied when inserting records.

Defaulted when?

Say we have a custom Sales Order object with an Order Date field that defaults to today’s date. To get some visibility of what’s going on during the insertion process, we’ll use a simple trigger:

trigger SalesOrder on SalesOrder__c (before insert)
{
    for(SalesOrder__c item : trigger.new)
        system.debug( 'Trigger Before: ' + item.OrderDate__c );
}

Now we insert a record via some Anonymous Apex:

SalesOrder__c salesOrder = new SalesOrder__c();
system.debug('New: ' + salesOrder.OrderDate__c);
insert salesOrder;
system.debug('Inserted: ' + salesOrder.OrderDate__c);
salesOrder = [select OrderDate__c from SalesOrder__c
    where Id=:salesOrder.Id];
system.debug('Reloaded: ' + salesOrder.OrderDate__c);

USER_DEBUG|[2]|DEBUG|New: null
USER_DEBUG|[4]|DEBUG|Trigger Before: 2013-06-03 00:00:00
USER_DEBUG|[4]|DEBUG|Inserted: null
USER_DEBUG|[7]|DEBUG|Reloaded: 2013-06-03 00:00:00

As we can see from the debug log, the default value is applied to our record some time between submitting the DML insert and the trigger being executed.

Visibility

We can also see that the default value is not immediately visible to us in our Anonymous Apex – either before or after inserting the record – we have to reload the inserted record to see the defaulted value.

Overriding

As you would expect, if we set our own value on the SObject before the insert, our value will be used in preference to the default value:

SalesOrder__c salesOrder = new SalesOrder__c();
salesOrder.OrderDate__c = Date.newInstance(2013,1,1);
insert salesOrder;

USER_DEBUG|[4]|DEBUG|Trigger Before: 2013-01-01 00:00:00

Overriding with null

What is interesting though, is that this holds even when the value we set is null:

SalesOrder__c salesOrder = new SalesOrder__c();
salesOrder.OrderDate__c = null;
insert salesOrder;

USER_DEBUG|[4]|DEBUG|Trigger Before: null

It seems therefore that there is an internal mechanism in the SObject which keeps track of whether or not the field has been set – you cannot set a field to null to mean “no value” and expect the default value to be used.

Checkboxes / booleans

This is particularly significant for checkbox fields. Whilst Apex boolean values have three states: null, false and true, SObject checkboxes do not have a null state, so when handling them conventionally in Apex, a checkbox value is returned either true or false.

You can set a checkbox to null, but its value will then be returned false.

However, when using dynamic Apex to access a checkbox field from a new SObject instance null will be returned if the field has not been explicitly set. 
Thanks to Alba Rivas for identifying this exception.

The loadDefaults argument

In Winter ’13 a very useful new feature was added for accessing default values in Apex. We can instantiate SObjects in Apex with default field values using the loadDefaults argument on the Schema.sObjectType newSObject method:

SalesOrder__c salesOrder = (SalesOrder__c)
    SalesOrder__c.sObjectType.newSObject(null,true);
system.debug('New: ' + salesOrder.OrderDate__c);
insert salesOrder;
system.debug('Inserted: ' + salesOrder.OrderDate__c);
salesOrder = [select OrderDate__c from SalesOrder__c
    where Id=:salesOrder.Id];
system.debug('Reloaded: ' + salesOrder.OrderDate__c);

USER_DEBUG|[2]|DEBUG|New: 2013-06-03 00:00:00
USER_DEBUG|[4]|DEBUG|Trigger Before: 2013-06-03 00:00:00
USER_DEBUG|[4]|DEBUG|Inserted: 2013-06-03 00:00:00
USER_DEBUG|[7]|DEBUG|Reloaded: 2013-06-03 00:00:00

Links

Force.com Apex Code Developer’s Guide – loadDefaults
Force.com Apex Code Developer’s Guide – Triggers and Order of Execution

This entry was posted in Documentation and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s