5

I am trying to figure out how to properly "bulkify" a trigger to handle mass deletes when launching an autolaunched flow. Documentation seems to be sparse on this. Will the flow bulkify itself if I instantiate it for every object in the collection, or do I need to use a set and loop through that before launching a flow (thinking this because the mass delete could include multiple of the same FundID parameter I am passing into the flow)?

Yes - I will move this to a trigger handler once I get some feedback on this.

Code below:

if(trigger.isDelete) 
{
    if(trigger.isAfter)
    {
         for (Manager_Contact_Relationship__c mcr : Trigger.Old){

             Map<String, Object> params = new Map<String, Object>();
             params.put('FundID', mcr.Manager_Fund__c);

             Flow.Interview.Update_MCR_Records MCRFlow = new Flow.Interview.Update_MCR_Records(params);

             MCRFlow.start();
         }
    }
}
  • Why are you trying to do the deletes in a flow and not just in APEX? – Fifedog Feb 22 '17 at 18:50
  • Im not doing deletes. Here is a better description of what I am trying to accomplish. I have two objects - Funds and Contact Relationships - in a Master-Detail fashion. Whenever the child object changes (i.e. update, insert, or delete), I am running a flow. The trigger fires off the child object in this case, the Manager Contact Relationship Object. Once it fires, I am passing the Parent Object ID to the flow. The flow finds all the Child objects of that parent, and passes them to an sObject Collection Variable. The flow loops through these children objects, and add the name of each record – Lucnex Feb 22 '17 at 20:23
  • to a text field, which is separated in a specific format. The end result is effectively a "roll-up summary field" which is a concatenated string of the children records. Upon completion this text string is updated on the Parent object. The reasoning for this is because salesforce reporting sucks, and we need the data in a very specific format to extract for consumption by other systems. Since I can handle updated and inserts in process builder, this isnt an issue. It is however an issue when I delete one of these children objects. Im worried if I bulkify my flow then I need to maintain – Lucnex Feb 22 '17 at 20:27
  • two separate flows, which I do not want to do. The reason behind using the flow is because the format can change, and we do not want to redeploy a class because of a simple formatting issue. Also, it allows other SFDC Admins to tweak it easily. Additionally, the likelihood of bulk deleting any of these records is effectively zero, it would be handled on a record by record basis. The org is also pretty small, and actually only about 10 people would be using this functionality @Fifedog – Lucnex Feb 22 '17 at 20:29
  • Ah... ok that makes sense and I've done the text concatenation before ;) I have an idea of a solution where I think you wouldn't have to call a flow from a trigger... – Fifedog Feb 23 '17 at 0:43
7

The system never optimizes triggers or flows of its own accord. You will need need to gather all the relevant ID values and then call the flow. However, you should be wary of using flows in bulk anyways, because they tend to consume a lot more CPU time than simply writing Apex Code. When you call a flow, it runs synchronously, as if you'd just called another method. They are not all gathered together and run asynchronously.

| improve this answer | |
  • Even if you pass in a list of relevant ID values, you still need to process each one through a fow loop. Any queries to the database from there are going to run through limits. – Matthew Metros Apr 18 at 22:24
5

You DO NOT want to be calling a flow 200 times from within a for loop in a trigger in the case that 200 Manager_Contact_Relationship__c records are deleted at once. Assuming your flow does any data retrieval (essentially SOQL queries) or saves any data to the database (DML statements), you have committed a cardinal sin against Apex best practices by putting it inside a for loop in a trigger.

As much as I'm skeptical about calling a flow from a trigger at all, due to the fact that it's hard to test and that a change to the flow can break the trigger and prevent these records for being deleted, I'd question the necessity for it at all.

But if you are going to do it, you should build your flow to accept a collection of IDs, and bulkify the flow the way you would a trigger - assume that you can get a collection of 200 IDs and make sure it can handle at least that many records without hitting any governor limits. I would suggest writing unit tests that test the result of the trigger + flow, so that you could have some kind of quality control on it.

| improve this answer | |
  • Is there any documentation on accepting collection variables in a flow? That would make my life a lot easier. The flow is simply checking calculating a csv field based on child records and inserting it onto the parent record. The variable that is passed is the child ID. The flow queries for all the children based on the parent of the child ID, passes it to a collection, and then iterates through them to construct a CSV of names. Once complete it inserts the updated CSV on the parent record. – Lucnex Feb 22 '17 at 15:56
  • Basically if I pass all the parent objects to a set, I still need to call a flow for each parent object, so that it can retrieve the collection before parsing them. The first element in the flow is a Fast Lookup, so I am unsure how I can pass a collection to this element and still get the flow to function properly – Lucnex Feb 22 '17 at 17:12
  • As long as the Flow has the input of a collection then calling the fast Delete shouldn't be a problem. The issue will be if you're looping through that collection first before the delete. Flows can only loop safely through 665 records, roughly pending on other elements, before you hit the element limits of flow. – Fifedog Feb 22 '17 at 18:53
1

OK what about this:

When a delete happens on your child, do an update to the parent, via a afterdelete() event. Let's set the textString you're populating to be 'recalculate'

Then create a processbuilder to look at the textString where when 'recalculate' to call your flow to look at all the child records and repopulate the text string?

Would that work?

| improve this answer | |
  • Thats an interesting idea - thanks for the suggestion. Its annoying I cannot pass in a collection to the flow in order for it to do a FastLookup based on something like a soql where in : collectionvariable, etc. Would this be better from a performance/limits perspective, since I am forcing the system to handle the bulkification? – Lucnex Feb 23 '17 at 19:21
  • I don't see why you couldn't pass in a collection, however, I've never tried. I've only ever trigged a flow from the PB side of the house so that's my limited knowledge and perspective. – Fifedog Feb 23 '17 at 20:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.