0

I have a Task in Salesforce with a custom record type of My Custom Record Type. This record type has a picklist field named My Custom Field and for this record type, I set the default value to My Default Value.

enter image description here

When a new Task is created, I want to set the record type in a before insert trigger. That is working:

trigger TaskTrigger on Task (before insert) {
    for (Task newTask : Trigger.new)  {
        Id recordTypeId = Schema.SObjectType
            .Task.getRecordTypeInfosByName()
            .get('My Custom Record Type')
            .getRecordTypeId()
        newTask.RecordTypeId = callTaskRecordType;
    }
}

However, after the insert, the default value of My Custom Field is not set. It is null

Task myTask = new Task();
insert myTask;

// Trigger logging executes, record type is set correctly...

Task insertedTask = [SELECT RecordTypeId, My_Custom_Field__c FROM Task WHERE Id = :myTask.id];

System.debug(insertedTask.RecordTypeId); // Set properly
System.debug(insertedTask.My_Custom_Field__c); // null!

Note that if I create a Task and set the record type before insert, the default value does get set correctly

Task myTask = new Task();
myTask.RecordTypeId = callTaskRecordType;
        Id recordTypeId = Schema.SObjectType
            .Task.getRecordTypeInfosByName()
            .get('My Custom Record Type')
            .getRecordTypeId()
        newTask.
insert myTask;

Task insertedTask = [SELECT RecordTypeId, My_Custom_Field__c FROM Task WHERE Id = :myTask.id];

System.debug(insertedTask.My_Custom_Field__c); // Set properly!

Why isn't the picklist getting the default value? And if this doesn't work, how could I set default values after changing the record type in a before insert?

2
  • Can you check the pick-list values on the Custom Record Type? Perhaps is not active? Commented Feb 27, 2020 at 19:39
  • The picklist value on the field (on Activity) is in the "Values" table, not the "Inactive Values" table
    – Andy Ray
    Commented Feb 27, 2020 at 19:45

2 Answers 2

3

This is expected, because the default values are applied at the beginning of the transaction, before almost anything else happens. It's already too late to apply the defaults once the record is already "in-flight." I'm actually not sure of a way to find the default value per picklist, as there's no Apex describe call that has this information that I'm aware of.

1
  • Ah, thank you. I certainly wish inconsistent behaviors like these were easier to debug, that's 6 hours of my life I'll never get back!
    – Andy Ray
    Commented Feb 27, 2020 at 20:14
1

If you look at the SObject class documentation you will find newSObject(recordTypeId, loadDefaults) you can use this to set the default values on the creation of a new object.

If you have to set the recordtypeid in the trigger and then wish for the default values to be written at that point in time you could do the following. There may be multiple reasons to not do this so please read and ensure you understand whats happening! Remember as it stands this will run for every task which is inserted so if you do not want fields overwritten on the source object being inserted then you will want to defend against it.

I'm interested if anyone has an opinion on this approach or an alternative solution.

Hope this helps someone

trigger TaskTrigger on Task (before insert) {

    //scope out fields for task object
    Map<String,Schema.SObjectField> taskFieldsMap = Task.SObjectType.getDescribe().getSobjectType().getDescribe().fields.getMap();

    for (Task newTask : Trigger.new)  {

        // would imagine you would want to wrap this in some kind of check? 

        // get your recordId
        Id recordTypeId = Schema.SObjectType
            .Task.getRecordTypeInfosByName()
            .get('My Custom Record Type')
            .getRecordTypeId();

        // create in memory task sobject with default field values for recordtypeid
        Sobject newTaskWithDefaultValues = Task.SObjectType.getDescribe().getSobjectType().newSObject(recordTypeId ,true);

        // create an Sobject reference to the task you are iterating in the trigger
        Sobject taskInScope = newTask;

        for(String taskFieldAPIName : taskFieldsMap.KeySet())
        {
           // get the fieldvalue from the in memory task we created with default values
           Object fieldValue = newTaskWithDefaultValues.get(taskFieldAPIName);
           // check if we have a default value for this task field api name
           if(null != fieldValue)
           {
               /* update the field on our in scope task with the field value 
                  from the one in memory - caution this is overwriting task fields
                  dynamically so if there are any fields you do not want overwriting 
                  then I suggest defending against it here */
               taskInScope.put(taskFieldAPIName, fieldValue);       
           }
        }
    }
}
2
  • If defaults are set at instantiation time, I don't understand why my last code snippet would work as it does
    – Andy Ray
    Commented Feb 27, 2020 at 22:38
  • I'll update the answer as that is not entirely clear, I was referring to the Sobject create method which will create defaults on instantiation so long as you tell it too.
    – Crispy
    Commented Feb 27, 2020 at 23:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .