triggerssalesforcebackendapex

Create 20000 caseComments after inserting a new Case


New to salesforce and Apex, i got a home task which im asked to create 20000 caseComments on a Case after insert. caseComments and Case are different objects but they are associated. i thought its going to be simple but the problems starts when reaching the DML limits of 10k per transaction.

I Tried to change the Inner and outer loops in my batch but nothing works, I'm able to create 9800 new CaseComments and if i cannot increase the Loop values even by 1 cause it will pass the limit.

The Trigger:

trigger CommentsOnCaseInsert on Case (after insert) {
    System.debug('Triggered');
    if (Trigger.isAfter && Trigger.isInsert && Trigger.new.size() == 1) {
        CreateCaseCommentsBatch batch = new CreateCaseCommentsBatch(Trigger.new[0].Id);
        Database.executeBatch(batch);
        
    }
}

The Batch job :

public class CreateCaseCommentsBatch implements Database.Batchable<SObject> {
    private Id caseId;
    public CreateCaseCommentsBatch(Id caseId) {
        this.caseId = caseId;
    }
   
    public Database.QueryLocator start(Database.BatchableContext context) {
        return Database.getQueryLocator([SELECT Id FROM Case WHERE Id = :caseId]);
    }
    // Execute method to create case comments
    public void execute(Database.BatchableContext context, List<Case> scope) {
        List<CaseComment> caseCommentsToInsert = new List<CaseComment>();
        for (Integer i = 0; i < 150; i++) { 
            for (Integer j = 0; j < 66; j++) {
                 Integer commentNumber = i * 66 + j + 1;
                CaseComment caseComment = new CaseComment(
                    ParentId = caseId,
                    CommentBody = 'Dummy Comment ' + commentNumber + ' - Of Case: ' + caseId
                );
                caseCommentsToInsert.add(caseComment);
            }
            insert caseCommentsToInsert;
            caseCommentsToInsert.clear();
        }
    }
    // Finish method `your text`
    public void finish(Database.BatchableContext context) {
    }
}

Solution

  • What you have won't work because your batch job is still going to call execute() only once. It'll be detached context from the main case trigger, with fresh set of limits - but still, just one. So same 10K DMLs applies.

    You could cheat by inserting 6666 in start(), execute() and finish(). Bit weak, stretching the solution but hey.

    You could look into daisy-chaining the batches (call Database.executeBatch() inside finish()). If you'd pair it with some counter variable passed like 5K done, do next chunk it could work fairly well. Maybe read up about Database.Stateful if you think you need such counter.

    Another option is Queueable, good for similar "are we there yet" work.

    Last but not least, there's option to call a batch with "Iterable" (start() method returns a list of things that doesn't have to come from database, can be created completely in memory... That'd be nice as in it'd call multiple execute()s 200 at a time or whatever... But I don't know how your memory usage would be if you were to create 20K case comments in memory and degrade executes to just inserting them.