Skip to main content
1 of 4
Daniel Ballinger
  • 103k
  • 40
  • 275
  • 601

Custom Metadata Type records are considered Metadata, and as such can't be inserted or updated directly via standard DML operations. Trying to do so will result in a TypeException with a message like:

System.TypeException: DML operation INSERT not allowed on ISVNamespace__MetadataTypeName__mdt

The Metadata namespace was added to Apex in Summer'17/v40.0 and provides the ability to deploy certain types of metadata asynchronously without having to resort the to Metadata API.

There is a good example of how this works in the Metadata Operations - Deploy Metadata documentation.

public class CreateMetadata{
  public void updateAndDeployMetadata() {
    // Setup custom metadata to be created in the subscriber org.
    Metadata.CustomMetadata customMetadata =  new Metadata.CustomMetadata();
    customMetadata.fullName = 'ISVNamespace__MetadataTypeName.MetadataRecordName';

    Metadata.CustomMetadataValue customField = new Metadata.CustomMetadataValue();
    customField.field = 'customField__c';
    customField.value = 'New value';

    customMetadata.values.add(customField);

    Metadata.DeployContainer mdContainer = new Metadata.DeployContainer();
    mdContainer.addMetadata(customMetadata);

    // Setup deploy callback, MyDeployCallback implements
    // the Metadata.DeployCallback interface (code for
    // this class not shown in this example)
    MyDeployCallback callback = new MyDeployCallback();

    // Enqueue custom metadata deployment
    Id jobId = Metadata.Operations.enqueueDeployment(mdContainer, callback);
  }
}

Note that this is an asynchronous operation and you need to provide a callback Apex class that implements the Metadata.DeployCallback interface.

This would be something like:

public class MyDeployCallback implements Metadata.DeployCallback {
    public void handleResult(Metadata.DeployResult result,
                             Metadata.DeployCallbackContext context) {
        Id jobId = context.getCallbackJobId();

        
        switch on (result.status) {
            when Succeeded {
                // Deployment was successful
            }
            when SucceededPartial {
                // The deployment succeeded, but some components might not have been successfully deployed. Check Metadata.DeployResult for more details.
            }
            when Failed {
                // Deployment was not successful
            }
            when Canceled {

            }
            when Pending, InProgress, Canceling {
                // Queued or state changing
            }
        }
    }
}

The DeployResult that comes back via the callback has a number of useful properties that correspond to monitoring an API based Metadata deployment result.

Daniel Ballinger
  • 103k
  • 40
  • 275
  • 601