1

I have a trigger handler class afterInsert() with following code:

public void afterInsert() {
       if(Handlerclass.isafterInsert){
            Handlerclass.isafterInsert = false;
                    Set<Id> documentIds = getDocIds(); //This method returns Document Ids to which we need to give access to other users under same account
                    Set<Id> availableUsers = new Set<Id>();
                    List<XYZ_Document__share> docshares = [SELECT UserOrGroupId FROM XYZ_Document__Share where ParentId in :documentIds WITH SECURITY_ENFORCED];                
                    for(XYZ_Document__share dc :docshares){
                        availableUsers.Add(dc.UserOrGroupId);
                    } 
                    docshares = New List<XYZ_Document__Share>();
                    List<User> portalUsers = [SELECT Id,Name,ContactId FROM User WHERE ContactId in :agentIds AND Id NOT IN :availableUsers];  
                    for(Id doc:documentIds){
                        for(User us :portalUsers){
                            XYZ_Document__Share share = new XYZ_Document__Share();
                            share.ParentId=doc;
                            share.UserOrGroupId = us.Id;
                            share.RowCause = 'Manual';
                            docshares.Add(share);
                        }    
                    }
                    if (docshares!=null && !docshares.isempty()){if(NG_AR_EMR_Document__share.sObjectType.getDescribe().isCreateable()){
                        insert docshares;
                        }else{
                            ExceptionUtility.logException('Error', 'Handlerclass', 'afterInsert', null, '', '', '', null);
                      
                    }
                } 

With less data the code is working fine but for huge data I'm getting Limit exception at insert. After checking logs I could see that if documentIds.size() = 170 and portalUsers.size() = 241, the total inserts are around 170*241=40970 and throwing 'System.LimitException: Too many DML rows: 10001'. Is there any way to refine my code or the nested for loops so that I can get rid of the Limit exception?

2 Answers 2

1

You could create a public group that contains all the users, then share the records to that group.

First, generate or identify a Group by some means. Then, create a list of GroupMember records, adding the users to the list. After that, create a list of share objects, sharing the record with the Group.

This will reduce the complexity to scale linearly with the number of users and records that need to share. It will also perform better by not specifying users individually.

1

About the only thing I think you can do here is to go async (it doesn't sound like reducing data volume is possible) and break up the insert list into multiple parts.

Using a batch class to do this (probably with the batch size determined by the size of the doc ids and portal users lists, e.g. Integer batchSize = 9000/docIds.size();) would be one way to handle it.

Another approach could be to use a Queueable class. Something like

public class SplitInsert implements Queueable {
    private List<SObject> data;

    // Good idea to set this to less than 10k just in case inserting a given SObject
    //   runs a trigger that itself performs some DML
    private static Integer rowLimit = 9000;

    public SplitInsert(List<SObject> givenData) {
        data = givenData;
    }

    public void execute(QueueableContext ctx) {
        // You'd want a metadata record (or something) so that you can
        //   manually intervene and stop execution in case things go awry
        List<SObject> recsToInsert = new List<SObject>();
        
        Integer totalRows = data.size();

        // Pick out some records that we can insert (without trying to remove
        //    things if the list has nothing left to remove)
        for(Integer i = 0; i < rowLimit && i < totalRows; i++) {
            // removing from the list will help us handle chaining
            recsToInsert.add(data.remove(0));
        }

        // No need to check if the list is empty
        // DML on an empty list is a no-op
        insert recsToInsert;

        if(!data.isEmpty()) {
            // We just need an instance of Queueable
            //   which this class is
            // Instance variables survive the transaction boundary, so
            //   by removing the rows we processed, we're only left with
            //   the data that hasn't yet been processed
            system.enqueueJob(this);
        }
    }
}

You must log in to answer this question.

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