2

I have written a trigger handler to prevent more than n incidents for a client(lookup to user) at any point of time. This handler behaves differently if choose (before insert, before update) i.e. the adderror exception occurs only after (n+1) incidents have been created but in case of (after insert,before insert) it works fine.So if the purpose of addError() is to prevent DML operations why does it allows that extra record in case of before events? Also how can I display a dynamic error message in a trigger context.

trigger CountLimit on Incident__c (before insert,before update,after undelete) {
    Set<Id> clientids = new Set<Id>();
    Map<Id,Integer> clientmap = new Map<Id,Integer>();

    for(Incident__c inc:Trigger.new)
    {
        clientids.add(inc.Client__c);
    }

    for(AggregateResult result:[select count(id) sum, client__c client from Incident__c where client__C in:clientids group by client__C])
    {
        clientmap.put((Id)result.get('client'),(Integer)result.get('sum'));
    }

     for(Incident__c inc:Trigger.new)
    {
        if(clientmap.get(inc.Client__c)>3)
        {
           inc.Client__c.addError('You can\'t open more than 3 incidents for '+ inc.Client__r.firstname+' '+inc.Client__r.lastname);
        }
    }
   } 
0

3 Answers 3

3

In the case of a before-trigger the query in the for-loop only returns three records in the AggregateResult, because the fourth record has not been inserted yet. In the case of an after-trigger, however, the record has already been inserted, so the query returns four records and the error shows.

I suggest that you change your code inside the last for-loop to:

if((Trigger.isUpdate && clientmap.get(inc.Client__c) > 3) || 
   (Trigger.isBefore && clientmap.get(inc.Client__c) > 2)) {
       inc.Client__c.addError('You can\'t open more than 3 incidents for '+ inc.Client__r.firstname+' '+inc.Client__r.lastname);
}

With regards to your dynamic message, you can't use object-relations this way in triggers. You will have to retrieve all clients first, add them to a map and then you can use them.

13
  • Thanks @koen, so I was defying logic here and it's best to put this handler under the events (after insert, after update, after undelete) for this particular scenario. Could you please advise on dynamic error message I mentioned in my original post? Because the error message converts to 'You can't open more than 3 incidents for null null'
    – Jarvis
    Commented Jan 21, 2015 at 6:32
  • No problem! If you decide to use after-events only, you can leave your code the way it is. I have updated my answer with a short explanation of what to do to get the dynamic messages to work, do you need an example? Commented Jan 21, 2015 at 8:22
  • hi @Koen, could you please help me in the test class below?It's throwing System.NullPointerException.
    – Jarvis
    Commented Jan 24, 2015 at 12:11
  • Koen, I think I get the issue here, until I annotate with @isTest(seealldata=true) I keep on getting this error.
    – Jarvis
    Commented Jan 24, 2015 at 13:54
  • 1
    UserRoleId = ur.Id, you use this line in CreateUser() but you don't set ur.Id in CreateUserRole(). If you want your UserRole to have an Id you need to insert it first and then use a SELECT query to retrieve it's Id. Commented Jan 29, 2015 at 10:32
1
  @isTest
public class IncidentLimit_Test {
    public static testmethod void testcountincident(){

        User usr = CreateUser('Ben','Bentaleb');
          List<Incident__c> inclist = new List<Incident__c>();  
        try{
        System.runAs(usr){
            Test.startTest();
            for(integer i=1;i<=5;i++)
            {
              inclist.add(new Incident__c(client__c=usr.id,Description__c='incident'+i));
            }
           insert inclist;
        Test.stopTest();
        }

    }

    catch(exception e){e.getmessage().contains('You can\'t open more than');}
        finally{System.assertEquals(5, inclist.size());}
    }
public static UserRole CreateUserRole(String name) {
    UserRole ur = new UserRole();
    ur.Name = name;
   insert ur;
    return ur;
}

    public static User CreateUser(String firstname, String lastname) {
    UserRole ur = CreateUserRole('Testing');
         profile pr = [SELECT Id FROM Profile WHERE Name='Standard User'];
    User usr = new User(FirstName = firstname,
                        LastName = lastname,
                        Username = firstname + '.' + lastname + '@testing.com',
                        IsActive = true,
                        UserRoleId = ur.Id,
                        Email = '[email protected]', 
                        Alias = 'tusr', 
                        TimeZoneSidKey = 'Europe/Berlin' , 
                        LocaleSidKey = 'en_US', 
                        EmailEncodingKey = 'UTF-8', 
                        ProfileId = pr.id, 
                        LanguageLocaleKey = 'en_US'
                        );
        insert usr;
    return usr;
}
}
0

This is how my final code looks like -

trigger CountLimit on Incident__c (after insert,after update,after undelete) {
    Set<Id> clientids = new Set<Id>();
    Map<Id,Integer> clientmap = new Map<Id,Integer>();

    for(Incident__c inc:Trigger.new)
    {
        clientids.add(inc.Client__c);
    }

    Map<Id,User> usermap = new Map<Id,User>([select id,name from user where id in:clientids]);

    for(AggregateResult result:[select count(id) sum, client__c client from Incident__c where client__C in:clientids group by client__C])
    {
        clientmap.put((Id)result.get('client'),(Integer)result.get('sum'));
    }

    for(Incident__c inc:Trigger.new)
    {
        if(clientmap.get(inc.Client__c)>5)
        {
           inc.addError('You can\'t open more than 5 incidents for '+ usermap.get(inc.Client__c));
        }
    }   
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .