DML class

one class to hold all changes made during any APEX operation


what it is

I created a master class called the "DML Class" to hold all transactions that could occur during an APEX execution. The class consists of a couple map and list variables, a constructor, and three methods to perform the dml operations and populate the variables. The maps are used to keep track of records to be deleted and updated. They have a key - value pair of Id - SObject. There is a list of SObjects to populate with values that are to be inserted.

he three methods comprise of a map populator, a map retriever, and a dml operation method. They are very simple and powerful methods to help reduce the number of dml operations carried out in a APEX execution. The code for these methods is listed below.


code structure

 
/*
    Organization :  CortezLabs
    Created Date :  August 2019
    Created By :    Scott Grimes

    Description : 
        Object to manage dml operations to sObjects across multiple methods
        Two classes are required for each dml operation (for Apex Error Log handling)
            DML object (Id --> record)
            ApexErrorLog (Id --> ApexErrorLog.Log) & (RecordName & ApexErrorLog.Log)
*/

public without sharing class DMLObject 
{
    // ------------------------------------------------------------------------------------------------
    // Variables
    private Map<String, Schema.SObjectType> objectTypeMap = Schema.getGlobalDescribe();
    public Map<Id, sObject> objectsToUpdate {get;set;}
    public Map<Id, sObject> objectsToDelete {get;set;}
    public List<sObject> objectsToInsert {get;set;}

    public Map<Id, ApexErrorLog.Error> objectsToUpdateErrorLogs {get;set;}
    public Map<Id, ApexErrorLog.Error> objectsToDeleteErrorLogs {get;set;}
    public Map<String, ApexErrorLog.Error> objectsToInsertErrorLogs {get;set;}


    // ------------------------------------------------------------------------------------------------
    // Controller
    public DMLObject() 
    {
        this.objectsToUpdate = new Map<Id, sObject>();
        this.objectsToDelete = new Map<Id, sObject>();
        this.objectsToInsert = new List<sObject>();

        this.objectsToUpdateErrorLogs = new Map<Id, ApexErrorLog.Error>();
        this.objectsToDeleteErrorLogs = new Map<Id, ApexErrorLog.Error>();
        this.objectsToInsertErrorLogs = new Map<String, ApexErrorLog.Error>();
    }


    /* ------------------------------------------------------------------------------------------------
        Created By :    Scott Grimes
        Created Date :  August 13th 2019
        Description : 
            Update the record value (or create a new sObject)
    */ 
    public void updateRecord(String objectType, Id objectId, String fieldLabel, Object fieldValue, String apexClass, String method, String operationType)
    {
        // Initialize the record
        sObject tempSObject = this.objectTypeMap.get(objectType).newSObject();
        tempSObject.put('Id', objectId);
        if(this.objectsToUpdate.containsKey(objectId)) {tempSObject = this.objectsToUpdate.get(objectId);}

        // Populate the value in the DML map 
        tempSObject.put(fieldLabel, fieldValue);
        this.objectsToUpdate.put(objectId, tempSObject);

        // Populate the value in ApexErrorLog map
        ApexErrorLog.Error newErrorLog = new ApexErrorLog.Error(apexClass, method, (String)objectId, objectType, operationType, null, null);
        this.objectsToUpdateErrorLogs.put(objectId, newErrorLog);

        // Remove from objectsToDelete & objectsToDeleteErrorLogs
        if(this.objectsToDelete.containsKey(objectId)) {
            this.objectsToDelete.remove(objectId);
            this.objectsToDeleteErrorLogs.remove(objectId);
        }
    }


    /* ------------------------------------------------------------------------------------------------
        Created By :    Scott Grimes
        Created Date :  August 13th 2019
        Description : 
            Get a record's value from the maps
    */ 
    public Object getRecordValue(String objectType, Id objectId, String fieldLabel, Object fieldValue)
    {
        // Initialize the record
        sObject tempSObject = this.objectTypeMap.get(objectType).newSObject();
        tempSObject.put('Id', objectId);

        // Get the value
        if(this.objectsToUpdate.containsKey(objectId)) {tempSObject = this.objectsToUpdate.get(objectId);}
        else {tempSObject.put(fieldLabel, fieldValue);}

        // Return the value
        return tempSObject.get(fieldLabel);
    }


    /* ------------------------------------------------------------------------------------------------
        Created By :    Scott Grimes
        Created Date :  August 13th 2019
        Description : 
            Bulkified DML Operation
    */ 
    public void dmlSObjectRecords()
    {
        // --------------------------------------------
        // Objects to Insert
        if(!this.objectsToInsert.isEmpty()) 
        {
            insertRecord();
        }

        // --------------------------------------------
        // Objects to Update
        if(!this.objectsToUpdate.isEmpty())
        {
            updateRecords();
        }

        // --------------------------------------------
        // Objects to Delete
        if(!this.objectsToDelete.isEmpty())
        {
            deleteRecords();
        }
    }
    
    // --------------------------------------------
    // Insert Records 
    public void insertRecord()
    {
        Database.SaveResult[] srInsertList = Database.insert(this.objectsToInsert, false);
        List<ApexErrorLog.Error> databaseErrors = new List<ApexErrorLog.Error>();
        for(Integer i=0; i<srInsertList.size(); i++) 
        {
            Database.SaveResult insertResult = srInsertList[i];
            // Check if the insert result was successful
            if(!insertResult.isSuccess()) {
                // Get the name of the failed record & get the related error log record
                //      NOTE --> srInsertList & this.objectsToInsert are in the same order
                String recordName = String.valueOf(this.objectsToInsert[i].get('Name'));
                if(!this.objectsToInsertErrorLogs.containsKey(recordName)) {continue;} // Check to make sure an ApexErrorLog exists
                ApexErrorLog.Error recordErrorLog = this.objectsToInsertErrorLogs.get(recordName);

                // Loop through the error messages
                for(Database.Error error : insertResult.getErrors()) {
                    // Update the error message
                    recordErrorLog.Message = error.getMessage();
                    recordErrorLog.ErrorCode = '' + error.getStatusCode(); // '' +  is required because getStatusCode() returns a "StatusCode" type record

                    // Add the error log record
                    databaseErrors.add(recordErrorLog);
                }
            }
        }

        if(!databaseErrors.isEmpty()) {ApexErrorLog.createLogs(databaseErrors);}
    }
    // --------------------------------------------
    // Update Records
    public void updateRecords()
    {
        Database.SaveResult[] srUpdateList = Database.update(this.objectsToUpdate.values(), false);
        List<ApexErrorLog.Error> databaseErrors = new List<ApexErrorLog.Error>();
        for(Integer i=0; i<srUpdateList.size(); i++) 
        {
            Database.SaveResult updateResult = srUpdateList[i];
            // Check if the insert result was successful
            if(!updateResult.isSuccess()) {
                // Get the name of the failed record & get the related error log record
                //      NOTE --> srUpdateList & this.objectsToUpdate are in the same order
                Id recordId = new List<Id>(this.objectsToUpdate.keySet())[i];
                if(!this.objectsToUpdateErrorLogs.containsKey(recordId)) {continue;} // Check to make sure an ApexErrorLog exists
                ApexErrorLog.Error recordErrorLog = this.objectsToUpdateErrorLogs.get(recordId);

                // Loop through the error messages
                for(Database.Error error : updateResult.getErrors()) {
                    // Update the error message
                    recordErrorLog.Message = error.getMessage();
                    recordErrorLog.ErrorCode = '' + error.getStatusCode(); // '' +  is required because getStatusCode() returns a "StatusCode" type record

                    // Add the error log record
                    databaseErrors.add(recordErrorLog);
                }
            }
        }

        if(!databaseErrors.isEmpty()) {ApexErrorLog.createLogs(databaseErrors);}
    }
    // --------------------------------------------
    // Delete Records
    public void deleteRecords()
    {
        Database.DeleteResult[] srDeleteList = Database.delete(this.objectsToDelete.values(), false);
        List<ApexErrorLog.Error> databaseErrors = new List<ApexErrorLog.Error>();
        for(Integer i=0; i<srDeleteList.size(); i++) 
        {
            Database.DeleteResult deleteResult = srDeleteList[i];
            // Check if the insert result was successful
            if(!deleteResult.isSuccess()) {
                // Get the name of the failed record & get the related error log record
                //      NOTE --> srDeleteList & this.objectsToDelete are in the same order
                Id recordId = new List<Id>(this.objectsToDelete.keySet())[i];
                if(!this.objectsToDeleteErrorLogs.containsKey(recordId)) {continue;} // Check to make sure an ApexErrorLog exists
                ApexErrorLog.Error recordErrorLog = this.objectsToDeleteErrorLogs.get(recordId);

                // Loop through the error messages
                for(Database.Error error : deleteResult.getErrors()) {
                    // Update the error message
                    recordErrorLog.Message = error.getMessage();
                    recordErrorLog.ErrorCode = '' + error.getStatusCode(); // '' +  is required because getStatusCode() returns a "StatusCode" type record

                    // Add the error log record
                    databaseErrors.add(recordErrorLog);
                }
            }
        }

        if(!databaseErrors.isEmpty()) {ApexErrorLog.createLogs(databaseErrors);}
    }
}

how to use it

I created the DML Class to be used in triggers, but it's methods can be applied to batch jobs and VFP controllers. Here is an example on how to call the methods in a trigger class method : 

 
// Insert new record
masterobject.ObjectsToInsert.add(
  new Account(
    Name = 'DML Class Account'
    Type = 'Prospect', 
    BillingStreet = '1234 Electric Avenue'
  )
);

// Update existing record
masterobject.UpdateRecord(
  'Account',        // Object type
  Account__c.Id,    // Record ID
  'OwnerId',        // Field label to update
  currentOwnerId    // Field value to use
);