1

I am new to Salesforce and trying to write a trigger and test class so that I can create a trigger that fires when the Active__c field on the Account object is updated to ‘No’. This trigger should find all related Case records and update their Status fields to ‘Closed’.

This trigger should create at least 150 Accounts and at least 10 Cases for each Account. ​I need to use assert statements to validate that my trigger is working.

I have written the below code and getting 3 errors:

Trigger:

trigger  AccountTrigger  on  Account   ( after update )   { 
Account.CaseUpdate(Trigger.new);
}


or 


trigger  AccountTrigger  on  Account   ( after update )   { 
CaseUpdate update = new CaseUpdate();
   if (Trigger.isAfter && Trigger.isUpdate){
        update.CaseUpdate(Trigger.new);
   }   
}

Class:

public class CaseUpdate {
       set <Account> accId = new Set <Id>();
       set <Cases> caseId = new Set <Id>();

  for (Case c : Trigger.new); {
  List<Case> opencase = [SELECT Id, Status, Account Id from Case where Id = :accId.Id];
 if (a.Active__c = 'No')
 {
  c.Status = 'Closed';
update opencase;
 } 
}
   }

Testclass:

@isTest
public   class   AccountTriggerTest  {
public   static  testMethod  void  doTest ()  {

    Account acc = new Account(
          Name = 'Test Account',

          Active__c = 'None'
       );
    insert acc;
       Case c = new Case(
           Account = acc.Id,
           Status = 'None';
       );
    insert c;
       Account accTest = [SELECT Id, Active__c FROM Account WHERE Id = :acc.id];
       System.assertEquals(accTest.Active__c, 'Yes');
       c.Status = 'Closed';
       update c;
       accTest = [SELECT Id, Active__C FROM Account WHERE Id = :acc.id];
       System.assertEquals(accTest.Status, 'Closed');
   }
}
}

Any suggestions and guidance would really help me. Thanks in advance.

5

Okay, so - You're doing a few things wrong, and crossing objects wrong in your trigger context.

First let's talk about your trigger:

trigger  AccountTrigger  on  Account   ( after update )   { 
    Account.CaseUpdate(Trigger.new);
}

On line 2, Account.CaseUpdate(Trigger.new) is not correct in this context. You are I assume trying to refer to the Account SObject, but in Salesforce you call methods via Class.Method, so since your class is called CaseUpdate you would want it to look like this instead:

trigger  AccountTrigger  on  Account   ( after update )   { 
    CaseUpdate.updateOnAfter(Trigger.new);
}

In the above, CaseUpdate is the name of my apex class, and updateOnAfter is the name of the method inside that class (more on this below).

Next, let's talk about your class:

public class CaseUpdate {
    set <Account> accId = new Set <Id>();
    set <Cases> caseId = new Set <Id>();

    for (Case c : Trigger.new) {
        List<Case> opencase = [SELECT Status, Account Id from Case where Id = :accId.Id];
        if (a.Active__c = 'No')
        {
            c.Status = 'Closed';
            update opencase;
        } 
    }
}

There are a few things you are doing wrong here...

Most importantly, you are doing a SOQL query and a DML update inside a for() loop. This is 100% not recommended on Salesforce because there are governor limits that restrict you to performing only a certain number of queries and DML statements in a single transaction. If you executed your above code on 100 or more records, you would reach the query limit, and if you removed the query but still left the dml, you would hit your DML limit at 150 records.

Tip: Instead of querying in the loop, you should query outside, prior to your loop, and then loop through your results, and instead of doing DML update inside of the loop for each record independently, you should create a List and add each updated case to the list, and then update the whole list outside/after the loop finishes.

Secondly, you haven't created a method within your class, so you have no method available to call from your Trigger. You need to define a method, and what that method returns (if anything), and also what parameters that method takes.

Thirdly, you are executing this trigger from the Account object, so the Trigger.new context has Account SObjects in it, but you are trying to do a for(Case c : Trigger.new) which you cannot do because the Trigger.new context is Accounts, not cases

Your class should look more like this:

public with sharing class CaseUpdate {
    public static void updateOnAfter(List<Account> newList){
        Set<Id> accId = new Set<Id>();
        List<Case> casesToUpdate = new List<Case>();

        for(Account a : newList){
            if(a.Active__c == 'No'){
                accId.add(a.Id);
            }
        }

        List<Case> caseList = [SELECT Status FROM Case WHERE AccountId IN :accId];

        for (Case c : caseList) {
            c.Status = 'Closed';
            casesToUpdate.add(c);
        }
        update casesToUpdate;
    }
}

Keep in mind, this is a very basic example - you may need to consider more code logic if its applicable to your business, and, if there is a possibility that an account may be edited again after being set to Active__c = No, then you'd likely also want to include the Trigger.oldMap in your method call and then check to see if the previous value wasn't already set to No, to avoid running the code unnecessarily on existing inactive accounts, like this:

Trigger:

trigger AccountTrigger on Account (after update ) {
    CaseUpdate.updateOnAfter(Trigger.new,Trigger.oldMap);
}

Class:

public with sharing class CaseUpdate {
    public static void updateOnAfter(List<Account> newList,Map<Id,Account> oldMap){
        Set<Id> accId = new Set<Id>();
        List<Case> casesToUpdate = new List<Case>();

        for(Account a : newList){
            if(a.Active__c == 'No' && !oldMap.get(a.Id).Active__c == 'No'){
                accId.add(a.Id);
            }
        }

        List<Case> caseList = [SELECT Status FROM Case WHERE AccountId IN :accId];

        for (Case c : caseList) {
            c.Status = 'Closed';
            casesToUpdate.add(c);
        }
        update casesToUpdate;
    }
}
  • Now that I think about it, I don't even think you technically need the List<Case> casesToUpdate = new List<Case>() because you're already modifying the contents of caseList so instead of adding them to casesToUpdate and then doing update casesToUpdate, you could just do update caseList, but I'm going to leave my answer as is because I think it provides clarity for updating lists outside of a loop – Morgan Marchese Dec 2 '16 at 14:33
  • Hi Morgan, Thanks for your revert. I used this but getting the below errors. Method does not exist or incorrect signature: Account.updateOnAfter(List<Account>, Map<Id,Account>) : line 2 Variable does not exist: c.Status ]: line 15 . My question we used the class name as CaseUpdate but why we are not calling the class through trigger. – Yogesh Kumar Dec 3 '16 at 0:16
  • Hey @YogeshKumar I apologize I made a very poor mistake in my final example, my last Trigger example with Account.updateOnAfter should actually be CaseUpdate.updateOnAfter(Trigger.new,Trigger.oldMap); – Morgan Marchese Dec 5 '16 at 15:44
  • Hey @YogeshKumar are you still having trouble with this or has this question been answered? – Morgan Marchese Dec 12 '16 at 15:48

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.