We have a process where when records are updated with Sync_Prospect_to_Pardot__c to true, it should create a pi__ObjectChangeLog__c record for every record updated. However, when I use the data loader to update 250 records with Bulk API enabled, only 200 pi__ObjectChangeLog__c records are created. If I have that setting unchecked, all 250 create. I logged a ticket with salesforce support and they said it's not an issue with the data loader and they won't provide feedback on the code as it is out of scope. Pardot support hasn't been helpful as we're using a custom process to create the object change logs. There's clearly something going on here and the code isn't anything different than what I've written for the rest of the org. We don't see issues using bulk api to fire off any of those processes.
The pi__ObjectChangeLog__c object is marked as "Allow Bulk API" access.
Is the issue the code? If not, what are some other things I need to check? I get the same results whether the starting sobject is a Contact or Lead.
Here's the components. Note we use Kevin O'Hara's SFDC Trigger Framework as recommended by Trailhead.
Trigger
trigger LeadTrigger on Lead (before insert, before update, before delete, after insert, after update, after delete, after undelete) {
Map<String, Trigger_Settings__c> triggerSettings = Trigger_Settings__c.getAll();
if(triggerSettings.get('LeadTrigger') <> null && triggerSettings.get('LeadTrigger').Execute_Trigger__c)
new LeadTriggerDispatcher().run();
}
Dispatcher
public without sharing class LeadTriggerDispatcher extends TriggerHandler {
//Trigger context variables are still available but need to be cast: trigger.new, trigger.newMap, trigger.oldMap
List<Lead> leads = (List<Lead>) trigger.new;
Map<Id, Lead> leadsOldMap = (Map<Id, Lead>) trigger.oldMap;
Map<Id, Lead> leadsNewMap = (Map<Id, Lead>) trigger.newMap;
Map<String, Trigger_Settings__c> triggerSettings = Trigger_Settings__c.getAll();
protected override void afterUpdate() {
//declare variables
Set<sObject> leadsForSync = new Set<sObject>();
//loop through to find qualifying records
for(Lead lead : leads) {
//leads are eligible for sync if their sync to prospect field changes, but no email changes were made. By default an OCL gets created if the email is updated
if(leadsOldMap.get(lead.Id).Sync_Prospect_to_Pardot__c == false && leadsNewMap.get(lead.Id).Sync_Prospect_to_Pardot__c == true)
leadsForSync.add((sObject)lead);
}
//execute methods
if(!leadsForSync.isEmpty() && !TriggerHandler.isBypassed('PardotSyncManager') && triggerSettings.get('PardotSyncManager') <> null && triggerSettings.get('PardotSyncManager').Execute_Trigger__c) {
TriggerHandler.bypass('PardotSyncManager');
PardotSyncManager.createObjectChangeLog(leadsForSync);
}
}
}
Class
public without sharing class PardotSyncManager {
//createObjectChangeLog takes a set of lead or contact records and creates an OCL record for those records. Called from the contact or lead dispatcher
public static void createObjectChangeLog(Set<sObject> records) {
system.debug('PardotSyncManager Start');
system.debug('records size: ' + records.size());
//oclsForInsert stores a list of OCLs that need to be inserted
List<pi__ObjectChangeLog__c> oclsForInsert = new List<pi__ObjectChangeLog__c>();
//Iterate through all records in the scope
for(sObject record : records) {
system.debug('record Ids: ' + record.Id);
//Check if the record is a contact. If so, then parse the sObject to a contact and then create an OCL for that contact.
if(String.valueOf(record.Id).substring(0,3) == '003') {
Contact contact = (Contact)record;
oclsForInsert.add(new pi__ObjectChangeLog__c(pi__ObjectEmail__c = contact.Email, pi__ObjectFid__c = contact.Id, pi__ObjectType__c = 1, pi__ObjectState__c = 1));
}
//Check if the record is a lead. If so, then parse the record into a lead and then create an OCL for that lead.
else if(String.valueOf(record.Id).substring(0,3) == '00Q') {
system.debug('lead qualified');
Lead lead = (Lead)record;
oclsForInsert.add(new pi__ObjectChangeLog__c(pi__ObjectEmail__c = lead.Email, pi__ObjectFid__c = lead.Id, pi__ObjectType__c = 2, pi__ObjectState__c = 1));
}
}
//try to insert the OCL records
try {
system.debug('ocls for insert: ' + oclsForInsert.size());
insert oclsForInsert;
}
//If there's an error, post the error to the debug log
catch(Exception e) {
system.debug('EXCEPTION in PardotSyncManager.createObjectChangeLog at row ' + e.getLineNumber() + ': ' + e.getMessage());
}
system.debug('PardotSyncManager Complete');
}
}
Map<String, Map<TriggerOperation, Set<Id>>
where the string is your "trigger name" and the rest is as per the other Q&A answer. This is effective in suppressing re-execution of a trigger against a specific record, by ID for a given operation, except before insert, within a given transaction/request/session.