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 –
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
- Now to update field values of existing custom metadata record, Create an instance of Custom Metadata object and map the fields accordingly.
- After mapping the fields in custom metadata object we need to create the container and add metadata instance to the container.
- Final step is to deploy the container.
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.
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