Salesforce, a robust platform, empowers developers to tailor and enhance its capabilities to address unique business requirements. This article delves into the process of programmatically creating a lookup field on an object using Apex and the MetadataService.cls.
Context
Lookup fields in Salesforce establish relationships between objects, enabling you to link records together. While creating lookup fields manually through the Salesforce UI is straightforward, there are scenarios where you might need to automate this process using Apex, especially when dealing with dynamic object creation or complex deployment scenarios.
Requirements
Before we delve into the code, make sure you have the following:
- A Salesforce developer account or sandbox environment.
- Apex knowledge.
- The MetadataService.cls class for interacting with the Metadata API. You can find it here.
Comprehending the Code
Breaking down the given Apex code:
Retrieve Session ID: The initial segment of the code obtains the user’s session ID through a Visualforce page. This session ID is essential for executing Metadata API calls.
<apex:page > Start_Of_Session_Id{!$Api.Session_ID}End_Of_Session_Id </apex:page>
Retrieve User Session ID: The fetchUserSessionId method retrieves the session ID from the content of the Visualforce page.
public static String fetchUserSessionId(){ String sessionId = ''; try{ PageReference reportPage = Page.getSessionIdVfPage; String vfContent = reportPage.getContent().toString(); Integer startP = vfContent.indexOf('Start_Of_Session_Id') + 'Start_Of_Session_Id'.length(), endP = vfContent.indexOf('End_Of_Session_Id'); sessionId = vfContent.substring(startP, endP); } catch(exception ex){ String msg = ex.getMessage(); Integer linenum = ex.getLineNumber(); return null; } return sessionId; }
Create Lookup Field: The createLookUpField
method utilizes the MetadataService.cls to create a lookup field on a specified object.
AuraEnabled public static String createLookUpField(String objName){ String sessionId = fetchUserSessionId(); System.debug('Session ID: ' + sessionId); MetadataService.MetadataPort service = new MetadataService.MetadataPort(); MetadataService.SessionHeader_element sessionHeader = new MetadataService.SessionHeader_element(); sessionHeader.sessionId = sessionId; service.SessionHeader = sessionHeader; MetadataService.CustomField customField = new MetadataService.CustomField(); customField.fullName = objName+'__c.'+'customLookUpField__c'; // it supposed to be object name . field name customField.label = Custom LookUp Field'; // lable for the field customField.type_x = 'Lookup'; // type of the field in this case we have lookup customField.relationshipLabel = 'Related ' + 'Lookup'; customField.relationshipName = 'Related_' + 'Lookup'; customField.referenceTo = objName; // Update with the object you want to reference List<MetadataService.SaveResult> results = service.createMetadata( new MetadataService.Metadata[] { customField }); System.debug('results : '+results); for (MetadataService.SaveResult result : results) { if (result.errors != null) { for (MetadataService.Error error : result.errors) { System.debug('Error message: ' + error.message); } } else { System.debug('Custom field created successfully: ' + result.fullName); //Give to field permission to the partuculler a field MetadataService.MetadataPort service1 = new MetadataService.MetadataPort(); service1.SessionHeader = new MetadataService.SessionHeader_element(); service1.SessionHeader.sessionId = sessionId; List<MetadataService.ProfileFieldLevelSecurity> profileFieldPermLst = new List<MetadataService.ProfileFieldLevelSecurity>(); MetadataService.ProfileFieldLevelSecurity profileFieldPermissions = new MetadataService.ProfileFieldLevelSecurity(); profileFieldPermissions.field = objName+'__c.'+'customLookUpField__c'; profileFieldPermissions.editable = true; profileFieldPermLst.add(profileFieldPermissions); MetadataService.Profile profile = new MetadataService.Profile(); profile.fullName = 'Admin'; // give system admin field permission profile.fieldPermissions = profileFieldPermLst; MetadataService.SaveResult[] results1 = service1.updateMetadata( new List<MetadataService.Metadata>{ profile }); } } }
Using the Code
To use the code, follow these steps:
- Upload the MetadataService.cls to your Salesforce organization.
- Call the
createLookUpField
method with the desired object name as a parameter.
String result = YourApexClass.createLookUpField('CustomObject'); System.debug(result);
Complete Code
Here’s the complete Apex code for your reference:
Vf Page :- Get Session ID <apex:page > Start_Of_Session_Id{!$Api.Session_ID}End_Of_Session_Id </apex:page> --------------------------------------------------------------------------------------------------- public static String fetchUserSessionId(){ String sessionId = ''; try{ PageReference reportPage = Page.getSessionIdVfPage; String vfContent = reportPage.getContent().toString(); Integer startP = vfContent.indexOf('Start_Of_Session_Id') + 'Start_Of_Session_Id'.length(), endP = vfContent.indexOf('End_Of_Session_Id'); sessionId = vfContent.substring(startP, endP); } catch(exception ex){ String msg = ex.getMessage(); Integer linenum = ex.getLineNumber(); return null; } return sessionId; } @AuraEnabled public static String createLookUpField(String objName){ String sessionId = fetchUserSessionId(); System.debug('Session ID: ' + sessionId); MetadataService.MetadataPort service = new MetadataService.MetadataPort(); MetadataService.SessionHeader_element sessionHeader = new MetadataService.SessionHeader_element(); sessionHeader.sessionId = sessionId; service.SessionHeader = sessionHeader; MetadataService.CustomField customField = new MetadataService.CustomField(); customField.fullName = objName+'__c.'+'customLookUpField__c'; // it supposed to be object name . field name customField.label = Custom LookUp Field'; // lable for the field customField.type_x = 'Lookup'; // type of the field in this case we have lookup customField.relationshipLabel = 'Related ' + 'Lookup'; customField.relationshipName = 'Related_' + 'Lookup'; customField.referenceTo = objName; // Update with the object you want to reference List<MetadataService.SaveResult> results = service.createMetadata( new MetadataService.Metadata[] { customField }); System.debug('results : '+results); for (MetadataService.SaveResult result : results) { if (result.errors != null) { for (MetadataService.Error error : result.errors) { System.debug('Error message: ' + error.message); } } else { System.debug('Custom field created successfully: ' + result.fullName); //Give to field permission to the partuculler a field MetadataService.MetadataPort service1 = new MetadataService.MetadataPort(); service1.SessionHeader = new MetadataService.SessionHeader_element(); service1.SessionHeader.sessionId = sessionId; List<MetadataService.ProfileFieldLevelSecurity> profileFieldPermLst = new List<MetadataService.ProfileFieldLevelSecurity>(); MetadataService.ProfileFieldLevelSecurity profileFieldPermissions = new MetadataService.ProfileFieldLevelSecurity(); profileFieldPermissions.field = objName+'__c.'+'customLookUpField__c'; profileFieldPermissions.editable = true; profileFieldPermLst.add(profileFieldPermissions); MetadataService.Profile profile = new MetadataService.Profile(); profile.fullName = 'Admin'; // give system admin field permission profile.fieldPermissions = profileFieldPermLst; MetadataService.SaveResult[] results1 = service1.updateMetadata( new List<MetadataService.Metadata>{ profile }); } } }
Summary
Automating the generation of lookup fields in Salesforce through Apex and MetadataService.cls equips developers with a robust mechanism for handling schema modifications programmatically. This method proves particularly valuable in situations involving dynamic object creation or intricate deployment processes.
Feel free to modify the code according to your specific needs and seamlessly incorporate it into your Salesforce development workflow.
Happy coding!