0

I need to create a trigger activated before update which updates the field Description from Case object. It updates Description with the concatenation of all CaseNumbers from child Cases, if there are child cases. If not, the Description will say 'Case without childs'. Here's the code i've made.

To access the child cases i want to compare the field parentId from all the cases to a list of the cases which activated the trigger. That's the first thing giving me an error. Next, i create a list of strings where i add the casenumber of cases sharing ParentId. Finally i want to check if the cases that activated the trigger have child, and change their Description. I get another error. The commented blocks are where the errors are appearing. Thanks in advance.

trigger CaseTrigger on Case (before update) {
    
    List<Case> casosHijos;
    List<Case> casosTrigger = [SELECT Id,ParentId FROM Case WHERE Id IN :Trigger.Old];
    for(Case c : [SELECT Id FROM Case]){
       /* if(c.ParentId == casosTrigger.Id){
           casosHijos.add(c);
        }*/
    }
    List<String> nombresCasosHijos = new List<String>();
    for(Integer i=0;i<casosHijos.size();i++){
        nombresCasosHijos.add(casosHijos[i].caseNumber);
       for(Integer j=0;j<casosHijos.size();j++){
          if(casosHijos[i].parentId == casosHijos[j].parentId){
              nombresCasosHijos[i] = nombresCasosHijos[i] + casosHijos[j].caseNumber;         
          }
       }
    }
    for(Case caso : Trigger.old){
        /*if(caso.id = casosHijos.ParentId){
        caso.Description = nombresCasosHijos;
        }*/
    }
}
2
  • Please edit your post to provide the complete, verbatim text of all errors and their locations so that the community can help you.
    – David Reed
    Mar 26, 2022 at 22:25
  • That said, there are a lot of issues with this trigger: it's bulkified incorrectly; the logic for concatenating child case numbers is incorrect and will "smear" data across parent records; the second set of commented lines contains a syntax error; and the trigger is running on the wrong DML event(s). I strongly recommend using the free and open source DLRS instead of writing your own rollup code, at least until you're much more familiar with Apex.
    – David Reed
    Mar 26, 2022 at 22:35

2 Answers 2

3

Both casosTrigger and casosHijos are Lists. The lists themselves do not have an Id. Even if they did, since they can contain multiple SObject records, which Id would it be?

A more appropriate choice here would be to use a Map. Maps allow you to correlate two pieces of information together. In your situation, I think a Map<Id, List<String>> would be appropriate. The key of the map would be the Id of your triggered cases, and the value would be the list of all of its child case numbers.

Building that map would look like this

Map<Id, List<String>> parentCaseToChildCaseNumbers = new Map<Id, List<String>>();

// Your goal here is to find child cases, so you want to find cases where
//   the _parent_ id is one of the cases in the trigger context variable
for(Case c :[SELECT Id, ParentId, CaseNumber FROM Case WHERE ParentId IN :trigger.newMap().keySet()]){
    // A short and efficient way to populate maps is to check to see if the
    //   map already contains our target key.
    // If it doesn't, add the key to the map with an empty value.
    if(!parentCaseToChildCaseNumbers.containsKey(c.ParentId)){
        parentCaseToChildCaseNumbers.put(c.ParentId, new List<String>());
    }

    // Because of the previous step, there will _always_ be something in the map
    //   that we can use (no need for an "else" block or a null check)
    parentCaseToChildCaseNumbers.get(c.ParentId).add(c.CaseNumber);
}

Your job after that point is to simply loop over trigger.new, and check if parentCaseToChildCaseNumbers.get(triggerCase.Id) is null.

If it is null, then you want to set the Description to "Caso sin hijos".
If it's not, then you can easily add all of the child case numbers using String.join() (which takes 2 arguments. 1) A list of strings. 2) The string you want to use to separate each string in the first list).

That is, if you have a List<String> myList = new List<String>{'a', 'b', 'c'};
String.join(myList, ', and ') would output 'a, and b, and c'

for(Case caso :trigger.new){
    List<String> numerosDeCasosHijos = parentCaseToChildCaseNumbers.get(caso.Id);

    if(numerosDeCasosHijos != null){
        // The list is not null, so combine its contents
        caso.Description = String.join(numerosDeCasosHijos, ', ');
    }else{
        // The list is null, so use some default text instead of the list
        caso.Description = 'Caso sin hijos';
    }

    // Another way to do this would be to use the ternary operator
    // result = <boolean condition> ? <expression if true> : <expression if false>
    //caso.Description = numerosDeCasosHijos != null ? String.join(numerosDeCasosHijos, ', ') : 'Caso sin hijos';

    // Yet another way is to use one value as a default, and then
    //   update the value if needed.
    // Saves a little bit of typing
    //caso.Description = 'Caso sin hijos';
    //if(numerosDeCasosHijos != null){
    //    caso.Description = String.join(numerosDeCasosHijos, ', ');
    //}
}

Remember

To take advantage of a "before" trigger's ability to update records without using DML, you need to make your changes to the instances of the records contained in either Trigger.new or Trigger.newMap.

Also

This trigger may not be of much use. If you have child cases related to a parent case, they can be displayed on the parent case's record detail page through a related list (which you can modify to display the case number).

4
  • I see my first mistake, in my query i was trying to compare the id values from the trigger to id, instead of ParentId. Thanks for your code, so useful, yet so simple to use a map Mar 26, 2022 at 23:20
  • Would it be something like this: for(Case caso : Trigger.New){ if(parentCaseToChildCaseNumbers.get(trigger.Id)) == null){ caso.Description = String.join(parentCaseToChildCaseNumbers.get(Id), ','); }else{ caso.Description = 'Caso sin hijos'; } } i've been reading about getSObjectType but i don't know if i'm doing it the right way. Mar 27, 2022 at 9:27
  • @alexmartinez You're close, but the if and else blocks are reversed. I'll edit my question to add that information.
    – Derek F
    Mar 27, 2022 at 11:53
  • Thank you so much for your help Derek, i've learnt a lot with you. And sorry if i've asked for too much, it's my first week with apex and i have a lot to learn. Mar 27, 2022 at 12:59
1

You can use a simple aggregate query to get the data you want:

Map<Id, AggregateResult> childCaseCount = new Map<Id, AggregateResult([
  Select ParentId Id, count(Id) sum
  From Case
  Where ParentId in :Trigger.new
  Group By ParentId]);
for(Case parent: Trigger.new) {
  AggregateResult ar = childCaseCount.get(parent.Id);
  if(ar == null) {
    parent. Description = 'No child cases.';
  } else {
    parent.Description = 'There are '+ar.get('sum') + 'cases.';
  }
}

You must log in to answer this question.

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