Wednesday, September 23, 2020

How to perform DML on Custom Metadata in Apex

 Custom Metadata Types are a great option when it comes to storing custom sets of data in Salesforce and building reusable functionality around it. You would have used custom metadata types too in your app but when we need to insert/update records using apex, we require different approach altogether as compared to DML on sObjects.

Before we get started with this, it’s important for you to understand basics about Custom Metadata. If you are new to Custom Metadata, then I’d recommend you to go through my previous blog which talks about Custom Metadata & its benefits.

Challenges

While updating custom metadata type records through apex class, we come across this error “DML operation Update not allowed on Metadata“. Why is this error? and the problem here is how to perform DML on Custom Metadata Types then? so let’s understand first why are we even getting this error and then let’s solve this by learning how we can create/update custom metadata using apex class.

Reason behind getting this error is we can’t currently manipulate Custom Metadata Types from Apex as they are considered Metadata.Since DML operations aren’t allowed on metadata in Apex with Partner or Enterprise APIs, it can be done only with the Apex Metadata API.In this blog, we will look at how to Create/Update Custom Metadata records using Apex.

Scenario

Provide different discounts to customers based on their previous purchases by storing Total Purchases for each customer along with their discount %.This scenario cover following requirements –

  • Customers Total purchase amount should be updated after every purchase
  • If the Total Purchase amount > 10,000, customers should get extra 10% discount
  • Customers should be eligible to get maximum discount of 70%
  • New customers will get 5% discount on their first purchase

Solution

Let’s create a custom metadata to store the customer Id, Total Purchase & discount % for the customers as shown below –

CustDiscountMetaData

Now create a apex class to access the custom metadata and write a logic to provide discounts to customers based on the total purchase amount-

Update Custom metadata record in Apex

To update custom metadata record in Apex, we have to follow below steps

  • First step is to get existing custom metadata record which we need to update

CM_query

  • Now to update field values of existing custom metadata record, Create an instance of Custom Metadata object and map the fields accordingly.

CM_update

  • After mapping the fields in custom metadata object we need to create the container and add metadata instance to the container.

CM_DeployContainer

  • Final step is to deploy the container.

CM_DeployContainer1

Note:  Boolean flag “isMetadataUpdateNeeded” check is added to make sure enqueue deployment is called only when there is a update on custom metadata.

Insert Custom metadata record in Apex

For our scenario,when a new customer purchases we will create new record in custom metadata.Assign a customerId and provide 5% discount on their first purchase.

  • Similar to update, In Insert also we need to create an instance of custom metadata and map fields accordingly. Only difference is we should set the DeveloperName and Label since we are creating a new record here.

CM_insert

References

Here’s the Complete class for your reference

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// Purpose: Store Security Credentials in custom metadata and perform update using Metadata API.
  
public class CustomerDiscountsCalculation{
      
    public static void updateDiscountInCustomMetadata(String CustomerId, Integer currentPurchase){
        Boolean isMetadataUpdateNeeded = false;
          
        //Get the customer record from Custom Metadata
        List<Customers_Discount__mdt> custDiscountDetail = [SELECT ID,MasterLabel,DeveloperName,Customer_Id__c,Discount__c,Total_Purchase__c
                                                            FROM Customers_Discount__mdt
                                                            WHERE Customer_Id__c =: CustomerId];
          
        //Create a deploy container which will be used for deploying(updating) the Custom Metadata Record
        Metadata.DeployContainer mdContainer = new Metadata.DeployContainer();
          
        if(!custDiscountDetail.isEmpty() && (custDiscountDetail[0].Total_Purchase__c + currentPurchase) > 10000){
              
            //create instance of Metadata.CustomMetadata
            Metadata.CustomMetadata metadataRec =  new Metadata.CustomMetadata();
            metadataRec.fullName = 'Customers_Discount__mdt.'+custDiscountDetail[0].De veloperName;
            metadataRec.label = custDiscountDetail[0].MasterLabel;
              
            //provide the value for the fields and add it to custom metadata instance
            Metadata.CustomMetadataValue totalPurchasetoUpdate = new Metadata.CustomMetadataValue();
            totalPurchasetoUpdate.field = 'Total_Purchase__c';
            totalPurchasetoUpdate.value = custDiscountDetail[0].Total_Purchase__c + currentPurchase;
            metadataRec.values.add(totalPurchasetoUpdate);
              
            if(custDiscountDetail[0].Discount__c <= 60){
                Metadata.CustomMetadataValue discounttoUpdate = new Metadata.CustomMetadataValue();
                discounttoUpdate.field = 'Discount__c';
                discounttoUpdate.value = custDiscountDetail[0].Discount__c + 10;
                  
            }
              
            //Add the custom metadata instances in the container
            mdContainer.addMetadata(metadataRec);
            isMetadataUpdateNeeded = true;
        }
        else if(custDiscountDetail.isEmpty()){
              
            //create instance of Metadata.CustomMetadata
            Metadata.CustomMetadata metadataRec =  new Metadata.CustomMetadata();
            metadataRec.fullName = 'Customers_Discount__mdt.'+CustomerId;
            metadataRec.label = CustomerId;
              
            //provide the value for the fields and add it to custom metadata instance
            Metadata.CustomMetadataValue totalPurchasetoUpdate = new Metadata.CustomMetadataValue();
            totalPurchasetoUpdate.field = 'Total_Purchase__c';
            totalPurchasetoUpdate.value = currentPurchase;
            metadataRec.values.add(totalPurchasetoUpdate);
              
            Metadata.CustomMetadataValue discounttoUpdate = new Metadata.CustomMetadataValue();
            discounttoUpdate.field = 'Discount__c';
            discounttoUpdate.value =  5;
            metadataRec.values.add(discounttoUpdate);
              
            //Add the custom metadata instances in the container
            mdContainer.addMetadata(metadataRec);
            isMetadataUpdateNeeded = true;
        }
          
        //Check if metadata deployment is required
        if(isMetadataUpdateNeeded)
        {
            // Enqueue custom metadata deployment and get the deployment id
            Metadata.Operations.enqueueDeployment(mdContainer, null);
        }
    }
}

No comments:

Post a Comment