Skip to content

Instantly share code, notes, and snippets.

@brianmfear
Created August 27, 2018 23:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brianmfear/cbfc5dd068bf78ba571ae56864dcc69e to your computer and use it in GitHub Desktop.
Save brianmfear/cbfc5dd068bf78ba571ae56864dcc69e to your computer and use it in GitHub Desktop.
Example of mapping related records to report errors on (Apex Code)
// Help report errors to parent/child object on failed DML update
// For use in Trigger contexts only.
// This version is for demonstration purposes only, and should not
// be considered production ready without additional modifications.
//
// Example trigger:
//
// trigger updateContactPhone on Account(after update) {
// Id[] updates = new Id[0];
// for(Account record: Trigger.new) {
// if(record.Phone != Trigger.oldMap.get(record.Id).Phone) {
// updates.add(record.Id);
// }
// }
// if(!updates.isEmpty()) {
// TriggerDmlHelper helper = new TriggerDmlHelper(List<Account>.class, List<Contact>.class);
// for(Contact record: [SELECT AccountId FROM Contact WHERE AccountId = :updates]) {
// Account triggerAccount = Trigger.newMap.get(record.AccountId);
// record.Phone = triggerAccount.Phone;
// helper.addMapping(triggerAccount, record);
// }
// helper.updateRecords('Failed to update {1}. First error was: {2}');
// }
// }
public class TriggerDmlHelper {
// Class to normalize various database.*result types.
class DmlResult {
Id recordId;
Integer rowIndex;
Boolean success;
Database.Error[] errors;
DmlResult(Boolean success, Id recordId, Database.Error[] errors, Integer rowIndex) {
this.success = success;
this.recordId = recordId;
this.errors = errors;
this.rowIndex = rowIndex;
}
}
// normalizes the various database.*result types for reportErrors
class DmlResultList implements Iterable<DmlResult> {
DmlResult[] genResults;
DmlResultList(Database.SaveResult[] results) {
genResults = new DmlResult[0];
for(Database.SaveResult result: results) {
genResults.add(new DmlResult(result.isSuccess(), result.getId(), result.getErrors(), genResults.size()));
}
}
DmlResultList(Database.DeleteResult[] results) {
genResults = new DmlResult[0];
for(Database.DeleteResult result: results) {
genResults.add(new DmlResult(result.isSuccess(), result.getId(), result.getErrors(), genResults.size()));
}
}
DmlResultList(Database.UndeleteResult[] results) {
genResults = new DmlResult[0];
for(Database.UndeleteResult result: results) {
genResults.add(new DmlResult(result.isSuccess(), result.getId(), result.getErrors(), genResults.size()));
}
}
public Iterator<DmlResult> iterator() {
return genResults.iterator();
}
}
// 1:1 mapping of which record is trying to update another record
SObject[] source, dest;
// Recommend using concrete types like List<Account> instead of List<SObject>
public TriggerDmlHelper(Type sourceType, Type destType) {
source = (SObject[])sourceType.newInstance();
dest = (SObject[])destType.newInstance();
}
// Adds another 1:1 mapping
public void addMapping(SObject src, SObject dst) {
source.add(src);
dest.add(dst);
}
// DML operations
public void insertRecords(String msg) {
reportErrors(new DmlResultList(Database.insert(dest, false)), msg);
}
public void updateRecords(String msg) {
reportErrors(new DmlResultList(Database.update(dest, false)), msg);
}
public void deleteRecords(String msg) {
reportErrors(new DmlResultList(Database.delete(dest, false)), msg);
}
public void undeleteRecords(String msg) {
reportErrors(new DmlResultList(Database.undelete(dest, false)), msg);
}
// For each failure, add an error to the source record
void reportErrors(DmlResultList results, String msg) {
Iterator<DmlResult> iter = results.iterator();
while(iter.hasNext()) {
DmlResult result = iter.next();
if(!result.success) {
source[result.rowIndex].addError(
String.format(
msg,
new String[] {
source[result.rowIndex].Id,
dest[result.rowIndex].Id,
result.errors[0].getMessage()
}
)
);
}
}
}
}
@sfdcale
Copy link

sfdcale commented Aug 28, 2018

Great example. I bookmarked it for future use.

I think the below line is missing 0 argument:

helper.updateRecords('Failed to update {1}. First error was: {2}');

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment