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.