Search code examples
triggerssalesforceapexapex-trigger

How do I make the trigger run after all the data is inserted into the batch class?


I want to use Apex Batch class to put 10,000 pieces of data into an object called A and use After Insert trigger to update the weight field value of 10,000 pieces of data to 100 if the largest number of weight fields is 100.

But now, if Batch size is 500, the number with the largest weight field value out of 500 data is applied to 500 data.

Of the following 500 data, the number with the largest weight field value applies to 500 data.

For example, if the weight field for the largest number of the first 500 data is 50,

Weight field value for data 1-50: 50

If the weight field for the largest number of the following 500 data is 100,

Weight field value for data 51-100: 100

I'm going to say that if the data is 10,000, the weight field is the largest number out of 10,000 data. I want to update the weight field value of all data.

How shall I do it? Here's the code for the trigger I wrote.

trigger myObjectTrigger on myObject_status__c (after insert) {


  List<myObject_status__c> objectStatusList = [SELECT Id,Weight FROM myObject_status__c WHERE Id IN: Trigger.newMap.KeySet() ORDER BY Weight DESC];


  Decimal maxWeight= [SELECT Id,Weight FROM myObject_status__c ORDER BY Weight DESC Limit 1].weight


  for(Integer i=0;i<objectStatusList();i++){

    objectStatusList[i].Weight = maxWeight;
  }
 
 update objectStatusList;
}

Solution

  • A trigger will not know whether the batch is still going on. Trigger works on scope of max 200 records at a time and normally sees only that. There are ways around it (create some static variable?) but even then it'd be limited to whatever is the batch's size, what came to single execute(). So if you're running in chunks of 500 - not even static in a trigger would help you.

    Couple ideas:

    • How exactly do you know it'll be 10K? You're inserting them based on on another record? You're using the "Iterator" variant of batch? Could you "prescan" the records you're about to insert, figure out the max weight, then apply it as you insert, eliminating the need for update?

    • if it's never going to be bigger than 10K (and there are no side effects, no DMLs running on update) - you could combine Database.Stateful and finish() method. Keep updating the max value as you go through executes(), then in finish() update them 1 last time. Cutting it real close though.

    • can you "daisy chain". Submit another batch from this batch's finish. Passing same records and the max you figured out.

    • can you stamp the records inserted in same batch with same value, like maybe put the batch job's id into a hidden field. Then have another batch (daisy chained?) that looks for them, finds the max in the given range and applies to any that share the batch job id but not have the value applied yet