You need to sign in to do that
Don't have an account?

addError method
I have an Account before trigger and if a bulk account update happens, I don't want to exit out the entire batch but check each account record but i can't really use database method or could i???
here is a sample code stub and check out my add error method. aList collection are records passed in from Trigger.new
Map<id, Contact> cMap= new Map<id, Contact>();
for (Contact c: cList){
cMap.put(c.AccountId, c);
}
for (Account a: aList){
if (cMap.containsKey(a.id)){
if( cMap.get(a.id).custom_field__c== null
&& cMap.get(a.id).custom_field__c==null ){
a.addError('missing contact info!);
}
If allOrNone is true, addError reverts entire DML operation. If an uncaught exception reaches the DML layer, the entire operation is reverted.
If allOrNone is false, then addError has a different effect. First, all records are attempted. If any return with an error on an object or field, those records are "set aside", the governor limits are reset, and a second pass occurs. If there are any further errors, a third pass is attempted, again with governor limits reset. At this point, if it fails, the operation fails and is rolled back. Otherwise, all records that passed the final pass without causing an error are all committed, while those that were "set aside" are flagged as errors and will be reported.
AddError will also work on any field or record bound to a Visualforce page; you can show an error message without any DML operation at all.
All Answers
I think you can use this method nly in following contexts:
Trigger.new in before insert and before updatetriggers, and on Trigger.old in before delete triggers
If allOrNone is true, addError reverts entire DML operation. If an uncaught exception reaches the DML layer, the entire operation is reverted.
If allOrNone is false, then addError has a different effect. First, all records are attempted. If any return with an error on an object or field, those records are "set aside", the governor limits are reset, and a second pass occurs. If there are any further errors, a third pass is attempted, again with governor limits reset. At this point, if it fails, the operation fails and is rolled back. Otherwise, all records that passed the final pass without causing an error are all committed, while those that were "set aside" are flagged as errors and will be reported.
AddError will also work on any field or record bound to a Visualforce page; you can show an error message without any DML operation at all.
sfdcfox-
thank you for the post but the problem is- this is a before update trigger. And from my understanding we don't need to explicilty write a dml (e.g. update account) or use a database.updatemethod. would I be able to use the database.update method in a before trigger?? My other question is, this is a trigger that throws an add error so there is no DML happening here. so how would i do a partial processing using the database.update and allOrNone parameter? here is what i was thikning:
List<Account> acctsToUpdate = new List<Account>();
Map<id, Contact> cMap= new Map<id, Contact>();
for (Contact c: cList){
cMap.put(c.AccountId, c);
}
for (Account a: aList){
if (cMap.containsKey(a.id)){
if( cMap.get(a.id).custom_field__c== null
&& cMap.get(a.id).custom_field__c==null ){
a.addError('missing contact info!);
}
else{
acctsToUpdate.add(a);
}
}
}
if(acctsToUpdate.size() >0){
database.update(acctsToUpdate,false);
}
A trigger runs inside of a DML event; you don't need to use on the records in the trigger, nor can you specify allOrNone, because the DML event is already underway. I think this is the piece that you're missing. Partial record processing isn't handled by the trigger, it's handled by the system. Consider the following code:
If you use the partial save button, one account is created, and the other is not; the trigger doesn't need to concern itself with partial saves explicitly, as the DML subsystem automatically handles the retry cases. The all or none save will fail, and no records will be inserted.
sfdcfox - i saw this in a similar thread but if i want to validate child objects so that if they don't meet a condition throw an error , otherwise perform a partial success using database method on a before trigger ,would this work or would processing come to a halt and exit the batch in this case
List<parent> plist = new List<parent>();
for(childObject child: childList){
if(child.my_custom__c == null ){
parentMap.get(child.ParentId).addError('not complete');
else{
parentList.add(parentMap.get(child.ParentId));
}
}
}
But what about this comment "If allOrNone is false, then addError has a different effect" - I thikn this effect happens when it is not a before trigger. Is tat correct? My goal is to check each parent record instead of existing the entire batch.
Reading again....since the before trigger is executed from a dml event, the record is already being updated since i'm within the context of a trigger so it's redundant to write another dml statement explicitly. So if i have a test method THEN i can explicilty write the logic to partially process those records in the event an addError is thrown. - i think i got this down now
Also to assert the message i think i need to recover them from a database method...looks like it should be database.error.getMessage(); correct?
2 more question is
1. if the records are triggered from a apex dataloader update- that is partial processing out of the box right?
2. If you are using database methods to examine each record, is there any reason to use try catch with a database method? seems like the catch block would never hit
for example:
badChilds is a list of records that meet the crtieria to throw the adderror
Test.startTest();
sfdcfox i got everything to work but having an issue getting coverage with a future method. how come my assert fails? is there a better way to test the future class..not sure the best way to reproduce an exception
//main class called from parent object trigger
try{
for(parentObject po: poList){
if(childObject.childfield__c == null ){
parentObjectMap.get(childObject.parentObjectId).addError(errMsg);
poList.add(oMap.get(childObject.parentObjectId));
}
}
System.debug('Currently, '+ myScriptLimit +' have been executed');
}
catch(Exception ex) {
futureElog.createElogRec(ex.getMessage());
}
}
}
//future class
global class futureElog {
@future
public static void createElogRec(string eMessage){
My_Error_Log__c eLogRec = new My_Error_Log__c(
Error_Description__c= eMessage);
insert eMessage;
}
}
Test.startTest();
integer beforeCount = [SELECT COUNT()
FROM My_Error_Log__c];
parentObject.id = '000000000000000000';
update opp;
Test.stopTest();
integer afterCount = [SELECT COUNT() FROM My_Error_Log__c];
System.AssertEquals(beforeCount +1, afterCount);
Ok..i was able to get the 100% coverage using isRunningtest() within the trigger and calling this before my catch in the main class. there was no other way to produce the exception from a trigger context
throw new TestException('err');