1

I try to write a trigger that set case status to "Closed" if thereare more than 2 cases created that same day (today) associated with the same contact. The problem is I don't want to use SOQL queries in for loops or nested for loops. I try to do it via map with a list as value, but can't get it working. I looked into this solution: Is there a way to get the list size from map<string,List<Sobject>>, but it gives me another for loop which makes it a nested for loop, which i try to prevent. Here is my code:

public without sharing class CaseStatusClosed {
    public static void triggerInjection(List<Case> caseList) {

        Set<Id> caseContactIdSet = new Set<Id>();
        Map<Id, Contact> contactById = new Map<Id, Contact>();
        //List<Case> caseAddList = new List<Case>();

        Map<Id, List<Case>> caseListByContactId = new Map<Id, List<Case>>();


        for(Case myCase : caseList){
            if(myCase.CreatedDate == Date.Today()){
                caseContactIdSet.add(myCase.ContactId);
                //caseAddList.add(myCase);
                if(!caseListByContactId.containsKey(myCase.ContactId)){
                    caseListByContactId.put(myCase.ContactId, new List<Case>());
                }
                caseListByContactId.get(myCase.ContactId).add(myCase);
            }
        }

        List<Contact> contList = [SELECT Id FROM Contact WHERE Id IN :caseContactIdSet];
        //Contacts related to cases Id of today

        for(Case myCase : caseList){


            if(caseListByContactId.get(myCase.ContactId) != null && caseListByContactId.get(myCase.ContactId).size() > 2){
                myCase.status = 'Closed';
            }
        }
    }
}

2 Answers 2

3

I don't think you're asking quite the right question here. Generally speaking, using a collection means that you'll also be using loops.

The code that you have right now looks pretty close to correct. Given that you have a Map<Id, List<Case>>, you already seem to know that you can use .get() on the map to fetch the stored List<Case>, and then call .size() to get the size of that list.

If you only have one or two contact Ids that you know you're looking for, you could do without the loop. In general though, a loop is the right tool for this job.

Instead, I suspect the issue with your code is that you're comparing a Date with a DateTime.

CreatedDate (contrary to its name) is actually a value of the DateTime type. Comparing a DateTime directly to a Date as you're doing will not work.

To illustrate, try running this code via anonymous apex

DateTime myDT = DateTime.newInstance(2020, 3, 30);
Date myDate = Date.newInstance(2020, 3, 30);

if(myDT == myDate){
    system.debug('Same day');
}else{
    system.debug('Different day');
}

You'll find that the system debug we get is "Different day"

If you make a small change though, it will work. DateTime has a method .date(), which extracts just the date from the DateTime. Since you're now comparing two Date instances to each other, it'll work as you expect.

Applied to your own code, change the following line

if(myCase.CreatedDate == Date.Today()){

to be this instead

// Note that we are now calling .date() to make sure we're comparing two dates
if(myCase.CreatedDate.date() == Date.Today()){

Some parting advice

Generally speaking, when you find that something "isn't working", that's only the first step in the bug-fixing journey. To be able to fix it, or get help in fixing it, you need to try to figure out what specific part(s) are the issue.

Personally, I tend to apply the following approach

  • Visually inspect the code, is there anything obviously wrong with it? (did I misspell something, use the wrong method, etc...)
  • Try to verify that specific things work like I think they should
    • This usually means taking a small part of the code, like caseListByContactId.get(myCase.ContactId).size() > 2, and writing just enough apex (via anonymous apex) to get a map<id, list<sobject>> populated so I can do a system.debug()
  • After that, I'll start from the known point of failure (Cases that should be getting closed aren't) and work backwards
    • Do we get into that final if statement at all?
    • Are we getting into that final loop at all?
    • Is the query for contList returning any rows?
    • etc...
  • Look at the execution logs, and add system.debug() to your code to see the values of variables, the results of expressions, or whether you're reaching a specific point in your code at all

The better picture you have of what's really going wrong, the easier time you'll have in fixing it.

0

Thanks for your help Derek, and you were completely right. I am a beginning developer so thanks for all the advises. I stored them in a Word document so i can always have it as a reference. As applying the System.debug method to debug my code, i stumbled upon a mistake in my code. Instead of getting the size from all cases in the database, I was getting the size of my constructor list. So with the help of your adjustment and my own debugging I figured out what went wrong and changed what was needed. Hereby my final code:

public  without sharing class CaseStatusClosed {
public static void triggerInjection(List<Case> caseList) {


    Map<Id, Contact> contactById = new Map<Id, Contact>();
    Map<Id, List<Case>> caseListByContactId = new Map<Id, List<Case>>();

    List<Case> caseQueryList = [SELECT Id, ContactId FROM Case WHERE CreatedDate = TODAY];

    for(Case myCase : caseQueryList){
        if(!caseListByContactId.containsKey(myCase.ContactId)){
            caseListByContactId.put(myCase.ContactId, new List<Case>());
        }
        caseListByContactId.get(myCase.ContactId).add(myCase);
    }


    for(Case myCase : caseList){
        System.debug(caseListByContactId.get(myCase.ContactId).size());
        if(caseListByContactId.get(myCase.ContactId) != null 
        && caseListByContactId.get(myCase.ContactId).size() > 2){

            myCase.status = 'Closed';
        }
    }
}

}

You must log in to answer this question.

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