Custom Metadata Records Deployment From Apex Code by using Metadata.Operations class enqueueDeployment method.
Code example, peculiarities, undocumented limitations, metadata relationships,
2. Introduction
Bohdan Dovhan - Senior Salesforce Developer and Salesforce Development Team Lead
Salesforce Certified Development Lifecycle & Deployment Designer
Salesforce Certified Platform Developer I
Salesforce Certified Platform Developer II
Salesforce Certified Platform App Builder
8 years of Development experience
5 years of Development on Salesforce platform
3. Long-long time ago
Long-long time ago in far-far away galaxy there were developers working on a
very-very legacy project on an internal Salesforce customizations. Later that
client company was acquired by a bigger company and a new integration with a
new external system of a bigger company was requested to be established.
This integration involved configuration records of country and state codes in
external database. Implementation of another subsidiary company which was
also acquired by a bigger company and which also used Salesforce, used
custom objects to store those country and code mappings. However, custom
objects records are not deployable, so these configuration mappings cannot be
migrated from sandbox to production environment during deployment.
Decision was made to convert those records from Custom Object and Custom
Metadata and to delegate this task to Junior Developer.
4. Unknown feature
Discovery was made that developers are not aware of of custom metadata records
deployment feature and might assume that team lead expect them to convert
those 5000 records manually.
Since I was surprised that such feature is not known amongst Salesforce
Developers, I decided to prepare this talk. Since this feature was introduced
more than year and a half ago, I supposed that everyone knows about it which
apparently is not completely true statement.
5. Data Example
Org based development vs. source driven development.
In a traditional SF Dev Lifecycle, application builders use sandboxes to create and
test changes. Source of truth is either production or any sandbox containing
most recent version of code and customization.
With Salesforce DX, you might use source driven development using latest
versions from a centralized source control system like GIT or SVN.
6. Operations class
Salesforce Summer 17 release introduced Metadata namespace and
Operations class inside it with the following capabilities:
1. Retrieval and deployment of custom metadata records
2. Retrieval and deployment of layouts
Well to retrieve custom metadata records we could just use SOQL
Retrieval and deployments of layouts is only relevant to package developers.
The most important feature here is ability to deploy custom metadata records by
Apex code
7. Metadata Loader
Wait, can’t we just use standard salesforce Custom Metadata Record Uploader package page?
Yes, but you will have to deploy this package to your organization and prepare CSV file.
Still, this application uses Metadata API under the hood while it could use Metadata.Operations class.
8. Metadata API
Wait, can’t we just use Metadata API?
Yes, but in such case you will have to add your organization endpoint to remote site settings and to use
complex WSDL classes for a simple task.
Also you can use Andrew Fawcett library which also utilizes Metadata API.
Since Metadata.Operations class doesn’t support deletion of metadata records, if you need to delete
custom metadata records you would still use Metadata API or libraries based on it
9. Records deployment
Let’s assume there are some mappings stored in Custom Objects records or Custom Settings.
Then enqueueDeployment method of Metadata.Operations class can be leveraged to write a simple
and concise code to convert those records into Custom Metadata records and those metadata
records can be migrated using ANT Migration Tool.
Since in most cases you don’t need to delete custom metadata records, this is a perfect fit for this task.
In case if you need to delete custom metadata records you could either build destructiveChanges.xml
and delete them using ANT Migration Tool or leverage Metadata API.
Deployment may either create a new custom metadata record or update existing custom metadata
records, depending on the uniqueness of the fullName attribute. If there is a custom metadata
record with a given DeveloperName, then that particular record will be updated with new values
during deployment but if such a record doesn’t exist, then a new record will be created during the
deployment process.
Also, the label attribute is, in fact, required even though it is not populated in the example from
documentation. I spent some time trying to figure this out when I was attempting to deploy custom
metadata records by Apex code, for the very first time.
10. Fields population
In order to populate a custom field on a Custom Metadata record, CustomMetadataValue model should
be instantiated and then it should be added to custom metadata record values. However, to populate
standard field on a Custom Metadata record one has to populate the label and fullName attributes
directly on a Custom Metadata record. Label and fullName attributes correspond to MasterLabel
and DeveloperName standard fields even though their names differ.
private Metadata.CustomMetadata makeMDTRecord(Sobject r) {
Metadata.CustomMetadata customMetadata = new Metadata.CustomMetadata();
customMetadata.fullName = populateName( r );
customMetadata.label = populateLabel( r );
for (SObjectField key: this.mappings.keySet() ) {
Metadata.CustomMetadataValue customField = new Metadata.CustomMetadataValue();
customField.field = String.valueOf(this.mappings.get(key) );
customField.value = r.get(key);
customMetadata.values.add(customField);
}
return customMetadata;
}
12. Code Example
The final example of code for records conversion is following
new MD().updateAndDeployMetadata(
[ SELECT Field1__c, Field2__c, Field3__c, Field4__c FROM Object__c ],
CustomMetadata__mdt.sObjectType,
new Map<SObjectField, SObjectField>{
Object__c.Field1__c=> CustomMetadata__mdt.Field1__c,
Object__c.Field2__c=> CustomMetadata__mdt.Field2__c,
Object__c.Field3__c=> CustomMetadata__mdt.Field3__c,
Object__c.Field4__c => CustomMetadata__mdt.Field4__c
},
'X+Field1__c+_+Field2__c’,
'Field3__c+ +Field4__c '
);
13. Metadata Relations
Also, when you need to populate a Custom Metadata relationship, you need to use DeveloperName
from the corresponding parent records instead of an identifier, which might seem odd since
everywhere else in Apex you either use Salesforce Id or External Id to populate relationships.
The same applies when you need to populate a Entity or Field relationship, the DeveloperName
from the corresponding Entity or Field should be used instead of Ids.
14. Undocumented limit
There are some undocumented limitations on a number of custom metadata records which can be
deployed by one call of a enqueueDeployment method of Operations class. The actual number
depends on the data included in the custom metadata records, and in my case I was able to deploy
around 1,488 custom metadata records at one time while trying to insert or update 1,489 records
yielded from an Salesforce System UnexpectedException Error.
Splitting custom metadata records into chunks and invoking a enqueueDeployment method several
times helps to deal with the issue
15. Package developers
There is “Deploy Metadata from Non-Certified Package Versions via Apex” checkbox setting, which enables beta
packages to perform a custom metadata records deployment from Apex code. This checkbox can be
found in Setup Build Develop Apex Settings menu in the setup configuration.
16. Package developers
So if you need to test the beta version of your developed managed package before passing a security
review, you will have to check this checkbox and save your settings on every organization where you
install a beta version of your package.
17. Metadata Relations
Metadata Relationships provide very convenient and useful way to dynamically store references to
SObjects and Fields. So you don’t need anymore to store
However, only some standard Objects are supported, so User object and User fields are not supported.
18.
19. Conclusion
As we can conclude now, the ability to deploy customization data directly from Apex code is a really great
and astonishing feature which has been available since the version 40 of Salesforce API. We have
considered here several use cases where this might be needed. Sometimes this can be useful for
developing interface to deploy custom metadata records from user experience, or this can be much
more useful and beneficial if you ever need to convert your existing customization data, stored in
Custom Objects or Custom Settings, in order to be able to include them into deployment scripts.