Establishing A Lookup Field In Salesforce Through Apex And MetadataService.cls

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!