0

I am curious what the rules are for using an update statement in a before insert trigger.

The below code is called during a before insert trigger on tasks. Basically what I am doing is saying "Hey, there is a new task associated with this opportunity. Let's check to see if there are any other open tasks associated with this opp. If there are, let's close them up"

public with sharing class NextStepDueDateTask 
{

    public static void handleTrigger(List<Task> newTasks) {

        Set<Id> OppIds = new Set<Id>();

        for(Task t: newTasks)
        {   
            // Grab all tasks that are related to Opportunities and are Open
            String s1 = t.WhatId != null ? String.valueof(t.WhatId) : '';  
            if(s1.startsWith('006') && t.status == 'Open')
            {
                OppIds.add(oppId);
            }
        }

        List<Opportunity> Opps = [ SELECT id, (SELECT id, status from Tasks WHERE status = 'open' ) from Opportunity where id in :OppIds ];

        set<Task> tasksToUpdate = new List<Task>();

        for(Opportunity opp : Opps)
        {
            if(opp.Tasks != null)
            {
                for( Task t : opp.Tasks  )
                {
                    t.Status = 'Completed';
                    tasksToUpdate.add(t);
                }
            }
        }

        update tasksToUpdate;
    }

1 Answer 1

2

Cross object logic definitively belongs in the after context. See Triggers:

There are two types of triggers:

  • Before triggers are used to update or validate record values before they’re saved to the database.
  • After triggers are used to access field values that are set by the system (such as a record's Id or LastModifiedDate field), and to affect changes in other records, such as logging into an audit table or firing asynchronous events with a queue. The records that fire the after trigger are read-only.

Again,

After triggers are used ... to affect changes in other records

If you are aiming to update sibling records, do so in an after trigger. If you want to just update records which look up to an Opportunity, that does belong in the before context, but should not invoke any DML Statements, and actually does not even require queries.

for (Task record : newTasks)
{
    if (record.WhatId != null && record.WhatId.getSObjectType() == Opportunity.sObjectType)
    {
        record.Status = 'Completed';
    }
}
2
  • nit: record.WhatId.getSObjectType sb record.WhatId.getSObjectType()
    – cropredy
    Commented Aug 15, 2019 at 22:04
  • @crop and the double == oops!
    – Adrian Larson
    Commented Aug 15, 2019 at 22:13

You must log in to answer this question.

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