0

Hi everyone im new to salesforce and im trying to put a trigger in place that would restrict me from creating a new custom object if it shares the same title (a custom field) as an existing one. Heres my code

trigger WorkItemTrigger on Work_Item__c (before insert) { 
   for(Work_Item__c newWorkItem : Trigger.New) { 
      for(Work_Item__c oldWorkItem : Trigger.Old) { 
         if(newWorkItem.Title__c == oldWorkItem.Title__c){ 
            newWorkItem.addError('No pueden haber 2 Work Items con titulos iguales.');
         }
      } 
   } 
}

And here is my code in the Anonymous window trying to test my change

Work_Item__c workItem = new Work_Item__c(Name='Work Item Test Name', Title__c='TestTrigger'); 
insert workItem;

I keep getting a NullPointerException at line 3. Anyone knows why? Will this give me an error if there are no old work items in the first place? Any advice would be much appreciated🙏

| improve this question | | | | |
  • Hi. The old values are only available for update (and delete) events, not insert events. You only receive the affected objects (new ones, updated ones, deleted ones) in the trigger. For what you want you need to perform an SOQL query to check there are no existing objects with the same title, and also check that each item in the new object list has a unique title too. – Phil W Jul 7 '19 at 22:08
  • 2
    Consider whether native Duplicate Management can meet your needs. Duplicate management in triggers is difficult to make performant. – David Reed Jul 7 '19 at 23:03
3

Salesforce provides context variables that are available during an execution context. As mentioned in the comment above, the Trigger.old variable is only available in update and delete triggers. The current trigger that you posted is running on before insert operations.

In that case, it would be necessary to do a SOQL query to fetch existing Work_Item__c records and verify if there is already an existing record with the same value on the Title__c field. This could be achieved with a straightforward approach:

trigger WorkItemTrigger on Work_Item__c (before insert) { 
    List<Work_Item__c> existingWorkItems = [ SELECT Id, Title__c FROM Work_Item__c ];
    for (Work_Item__c newWorkItem : Trigger.New) { 
        for (Work_Item__c existingItem : existingWorkItems) {
            if (newWorkItem.Title__c == existingItem.Title__c) {
                newWorkItem.addError('No pueden haber 2 Work Items con titulos iguales.');
            }
        }
    }
}

However, this approach could reach either CPU or records retrieved limits given the use of nested for loops. A better approach could be achieved by making use of the Map collection type:

trigger WorkItemTrigger on Work_Item__c (before insert) { 
    Map<String, Work_Item__c> workItemByTitle = new Map<String, Work_Item__c>();
    for (Work_Item__c newWorkItem : Trigger.New) { 
        workItemByTitle.put(newWorkItem.Title__c, newWorkItem);
    }

    List<Work_Item__c> existingWorkItems = [ SELECT Id, Title__c FROM Work_Item__c WHERE Title__c IN :workItemByTitle.keySet() ];
    if (!existingWorkItems.isEmpty()) {
        Work_Item__c duplicateWorkItem;
        for (Work_Item__c existingWorkItem : existingWorkItems) {
            duplicateWorkItem = workItemByTitle.get(existingWorkItem.Title__c);
            duplicateWorkItem.addError('No pueden haber 2 Work Items con titulos iguales.');
        }
    }
}

Lastly, I would also recommend to not include business logic within triggers for maintainability and decoupling purposes. You could use a simple trigger handler/helper design pattern instead.

| improve this answer | | | | |
  • This was exactly what i was looking for. Straight up to the point while pointing out the best practices. Thanks Mate! – JPG Jul 7 '19 at 23:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.