Monday, November 29, 2021

Create One to One Relationship in Salesforce

 Basically Salesforce offers two types of relationship:

  • One To Many Relationship
  • Many To Many Relationship (Using the concept of Junction object)

Sometimes we may need One To One relationship, But unfortunately Salesforce doesn’t allow any direct methodology to build One To one relationship.

Let’s consider the scenario that we want to establish a One to One relationship between two custom objects Employee__c and PAN_Card__c.

So, here are few ways to implement One To One relationship between two objects in Salesforce. We can achieve this by using configuration only and can also achieve this by using code to make it more scalable.

Option 1:

  • Create a lookup field on PAN_Card__c to Employee__c.
  • Create a custom field on the PAN_Card__c object and make the field unique. This field would be used to hold the ID of the associated Employee__c. Hide this field from all page layouts.
  • Create a Workflow rule on PAN_Card__c. For any change of the lookup field on PAN_Card__c object, update the custom field on the PAN_Card__c object with the value of the associated Employee Id.

We have established a one to one relationship between PAN_Card__c and Employee__c. When we try to add a second PAN_Card__c to the Employee__c, the “unique” constraint would be violated and an error would be thrown. This approach will work on both standard and custom object.

Option 2:

  • Create a master detail relationship on PAN_Card__c to Employee__c object.
  • Create a roll up summary field on Employee__c object of PAN_Card__c with count type.
  • Create a validation rule on Employee__c object rollup summary field to check if count > 1.

In this way also, We have established a one to one relationship between PAN_Card__c and Employee__c. So it will throw an error if Employee__c has more than one PAN Card.

Option 3:

  • Create lookup fields on both objects PAN_Card__c and Employee__c, to each other.
  • Write triggers, for any change on these lookups, to either copy the record ID into the other object’s lookup field when the other object’s lookup field is empty, or disallow the change to the original record when the other object’s lookup field is already populated with a different ID from the original record.

This is already having a one-to-onePassport relation.

Option 4:

  • Create a trigger on PAN_Card__c object to check if the PAN Card record already exists for an Employee. If it exist, then throw an error, else allow the user to create.
    Here is the example for Employee__c and PAN_Card__c object:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    trigger PANCardValidation on PAN_Card__c (before insert, before update) {
        Set<id> employeeIds = new Set<id>();
        Map<id, Employee__c> mapEmployee = new Map<id, Employee__c>();
      
        for (PAN_Card__c p : trigger.New) {
            employeeIds.add(p.Employee__c);
        }
      
        List<Employee__c> lstEmployee = [SELECT Id, Name FROM Employee__c WHERE Id IN : employeeIds];
        if (!lstEmployee.isEmpty()) {
            for (Employee__c emp : lstEmployee) {
                mapEmployee.put(emp.Id, emp);
            }
      
            for (PAN_Card__c p : trigger.New) {
                if (mapEmployee.containsKey(p.Employee__c)) {
                    p.addError('A PAN Card already exist for the employee - ' + mapEmployee.get(p.Employee__c).Name);
                }
            }
        }
    }

Database.SaveResult[] in Salesforce

 

DML Statements vs. Database Class Methods


Apex offers two ways to perform DML operations: using DML statements or Database class methods. This provides flexibility in how you perform data operations. DML statements are more straightforward to use and result in exceptions that you can handle in your code.

This is an example of a DML statement to insert a new record.


// Create the list of sObjects to insert

List<Account> acctList = new List<Account>();

acctList.add(new Account(Name='Acme1'));

acctList.add(new Account(Name='Acme2'));


// DML statement

insert acctList;


This is an equivalent example to the previous one but it uses a method of the Database class instead of the DML verb.


// Create the list of sObjects to insert

List<Account> acctList = new List<Account>();

acctList.add(new Account(Name='Acme1'));

acctList.add(new Account(Name='Acme2'));


// DML statement

Database.SaveResult[] srList = Database.insert(acctList, false);


// Iterate through each returned result

for (Database.SaveResult sr : srList) {

    if (sr.isSuccess()) {

        // Operation was successful, so get the ID of the record that was processed

        System.debug('Successfully inserted account. Account ID: ' + sr.getId());

    }

    else {

        // Operation failed, so get all errors                

        for(Database.Error err : sr.getErrors()) {

            System.debug('The following error has occurred.');                    

            System.debug(err.getStatusCode() + ': ' + err.getMessage());

            System.debug('Account fields that affected this error: ' + err.getFields());

        }

    }

}


One difference between the two options is that by using the Database class method, you can specify whether or not to allow for partial record processing if errors are encountered. You can do so by passing an additional second Boolean parameter. If you specify false for this parameter and if a record fails, the remainder of DML operations can still succeed. Also, instead of exceptions, a result object array (or one result object if only one sObject was passed in) is returned containing the status of each operation and any errors encountered. By default, this optional parameter is true, which means that if at least one sObject can’t be processed, all remaining sObjects won’t and an exception will be thrown for the record that causes a failure.

The following helps you decide when you want to use DML statements or Database class methods.

  • Use DML statements if you want any error that occurs during bulk DML processing to be thrown as an Apex exception that immediately interrupts control flow (by using try. . .catch blocks). This behavior is similar to the way exceptions are handled in most database procedural languages.
  • Use Database class methods if you want to allow the partial success of a bulk DML operation—if a record fails, the remainder of the DML operation can still succeed. Your application can then inspect the rejected records and possibly retry the operation. When using this form, you can write code that never throws DML exception errors. Instead, your code can use the appropriate results array to judge success or failure. Note that Database methods also include a syntax that supports thrown exceptions, similar to DML statements.

Note

Most operations overlap between the two, except for a few.

  • The convertLead operation is only available as a Database class method, not as a DML statement.
  • The Database class also provides methods not available as DML statements, such as methods transaction control and rollback, emptying the Recycle Bin, and methods related to SOQL queries.