0

Can any one help me out.I shall appreciate your help.

I have trigger written for the Duplicate case to be closed once it is identified as a duplicate with same subject line.But my trigger throws an

ERROR : as Error: Invalid Data. Review all error messages below to correct your data.Apex trigger Case_DuplicateClose caused an unexpected exception, contact your administrator:Case_DuplicateClose: execution of AfterInsert caused by: System.FinalException: Record is read-only: Trigger.Case_DuplicateClose: line 30, column 1.

If i just comment the set id line :it throws an ERROR for my first case itself.I think Somewhere my trigger is wrong

CODE :

trigger Case_DuplicateClose on case (after insert)
{
  Map<String, List<Case>> subjectToCaseList = new Map<String, List<Case>>();

  //set<id> CaseID = new set<id>();

  for(Case c : trigger.new)

  {   //CaseID.add(c.id);

    // System.debug('@@@@@@@@@@@@@@@@@@@@@@@' + );

    if(subjectToCaseList.get(c.Subject) != null)
    {
      subjectToCaseList.get(c.Subject).add(c);
    }
    else
    {
      subjectToCaseList.put(c.Subject, new List<Case> {c});
    }
  }

  // any results from this query are dupes based solely on subject
  for(Case existingCase : [select Id, Subject from Case where Subject in : subjectToCaseList.keySet()])
  {
    for(Case newCase : subjectToCaseList.get(existingCase.Subject))
    { 
      newCase.addError('This case is a duplicate.');

      //newCase.Status = 'Closed';
    }
  }
}
2
  • @BarCotter:Before Commenting the line i got an Error as "Record is read only".After Commenting the lines in the code :i got the other Error as :This case is a duplicate ,for the creation of my first case.But this Error should come when we are creating a second case withe same subject line.But case should be closed once it is identified as a duplicate case with same subject line.
    – nikkey
    Commented Sep 26, 2014 at 10:02
  • Sorry, I deleted my comment when I realised that you mentioned in the question that you had commented out that line
    – BarCotter
    Commented Sep 26, 2014 at 10:21

2 Answers 2

0

You are running trigger on after insert event. In after trigger record becomes read-only. You should run trigger on "before" if you want to change value in field in current record. After trigger are used to update other objects record which are not part of current trigger context.

trigger Case_DuplicateClose on case (before insert)
{
  Map<String, List<Case>> subjectToCaseList = new Map<String, List<Case>>();

  //set<id> CaseID = new set<id>();

  .......
  .......

 // any results from this query are dupes based solely on subject
  for(Case existingCase : [select Id, Subject from Case where Subject in : subjectToCaseList.keySet()])
  {
    for(Case newCase : subjectToCaseList.get(existingCase.Subject))
    { 
      newCase.addError('This case is a duplicate.');

      newCase.Status = 'Closed';
    }
  }
}
3
  • :Thanks for you reply.But my trigger should run in after insert.First the case should get created and then get identified as a duplicate case having same subject line and get closed.
    – nikkey
    Commented Sep 26, 2014 at 9:45
  • you can also identify duplicate record in before insert event. It will have all values which should be in after insert except system fields. Also you are adding error to record so if there is duplicate found this record will not be inserted. There seems no logic of updating status to close. @nikkey
    – Ashwani
    Commented Sep 26, 2014 at 10:02
  • :i was just testing with the add error function for the duplicates to get identified and then commented the code and added with the Status to be closed .im looking for o/p something like this as:1st case created say caseA where the Status is open.Again another case created 2nd case say CaseB with same subject line as of caseA,Now the system should identify the second case as a duplicate case with same subject line and get closed by adding its case comment(CaseB) to the first case (CaseA) which is open.For this we need to use After trigger implemenation.
    – nikkey
    Commented Sep 26, 2014 at 10:48
0

As @Regal said, the records become read-only in the after trigger. i.e. you can not edit any SObject instance that Trigger.new returns.

You can however edit records that you have queried. The code snippet below shows how to do it.

...
List<Case> toUpdate = new List<Case>();
for(Case existingCase : [select Id, Subject from Case where Subject in : subjectToCaseList.keySet() and Status = 'Open']) {
    for(Case newCase : subjectToCaseList.get(existingCase.Subject)) { 
        if (newCase.Id == existingCase.Id) {   
            existingCase.Status = 'Closed';
            toUpdate.add(existingCase);
        }
    }
}
if (toUpdate.size() > 0) {
    update toUpdate;
}

NB: The major downfall of doing this is that update toUpdate; causes the Case triggers to fire again. You won't have an recursion because you are only using an after insert trigger, but you need to be aware that triggers will fire again with this approach.

The query will find all the cases, include the cases that have just been inserted. You would need to add some logic that will be able to detect when there is 2 or more cases with the same subject, otherwise this approach will close all cases that are entered.


I don't see any reason why you couldn't implement the same logic in a before trigger. The code below would detect duplicates and close them.

trigger Case_DuplicateClose on Case (before insert) {
    List<String> newSubjects = new List<Subjects>();
    for (Case c : trigger.new) {
        if (c.Status == 'Open') {
            newSubjects.add(c.Subject);
        }
    }

    Set<String> existingSubjects = new Set<Subjects>();
    for (Case c : [select Subject from Case where Subject in :newSubjects and Status = 'Open']) {
        existingSubjects.add(c.Subject);
    }
    for (Case c : trigger.new) {
        if (existingSubjects.contains(c.Subject) != null) {
           c.Status = 'Closed';
        }
    }
}
5
  • :Thanks for your help.i have added the code with list ,but the trigger gets fired for the 1st case and get closed .im looking for o/p something like this as:1st case created say caseA where the Status is open.Again another case created 2nd case say CaseB with same subject line as of caseA,Now the second case should be identified as a duplicate case with same subject line and get closed.
    – nikkey
    Commented Sep 26, 2014 at 10:27
  • I have updated my answer so that it's also checking the Status. The before trigger implementation would avoid that issue
    – BarCotter
    Commented Sep 26, 2014 at 10:29
  • :i do get an Error as ;Error: Compile Error: Method does not exist or incorrect signature: [SET<String>].put(String) at line 11 column 9.im looking for o/p something like this as:1st case created say caseA where the Status is open.Again another case created 2nd case say CaseB with same subject line as of caseA,Now the system should identify the second case as a duplicate case with same subject line and get closed by adding its case comment(CaseB) to the first case (CaseA) which is open.For this we need to use After trigger implemenation
    – nikkey
    Commented Sep 26, 2014 at 10:51
  • @Nikkey we are here to help when you are stuck on an issue. The code samples I provided are enough to fix your "Record is read-only" error and show you how to update a record in an after trigger. Ive fixed the compile errors you were seeing. I suggest you try to figure out your own logic to solve your problem. If you are still stuck then ask another question.
    – BarCotter
    Commented Sep 26, 2014 at 10:59
  • One solution would be to order the SOQL results by CreatedDate so that the for look will iterate from oldest to newest. The first Case with Subject X will be the one to keep open. The rest with Subject X will be the ones you need to close.
    – BarCotter
    Commented Sep 26, 2014 at 11:01

You must log in to answer this question.

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