function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Learning Apex (OOP)Learning Apex (OOP) 

Concept of after insert

Hello,

The apex code below is resolving the following requirement (specified as an exercises for practice):

When an opportunity is inserted, automatically add the Oppty's Owner's Manager as a Team Member (of the Opportunity being inserted), with the role "Sales Manager".

The solution provided by the exercise's author is below:
trigger OwnerManager on Opportunity (after insert) {
    for(Opportunity opp : Trigger.new){
        //Get opp owner manager info
        Opportunity oppWithManagerInfo = [SELECT Id,
                                                 Owner.ManagerId
                                            FROM Opportunity
                                           WHERE Id = :opp.Id];
        //Create Opportunity Team Role
        if (oppWithManagerInfo.Owner.ManagerId != null) {
            OpportunityTeamMember otm = new OpportunityTeamMember();
            otm.UserId                = oppWithManagerInfo.Owner.ManagerId;
            otm.OpportunityId         = opp.Id;
            otm.TeamMemberRole        = 'Sales Manager';
            insert otm;
        }
    }
}
My question is regarding Line 7 --> WHERE Id = :opp.Id

The question is: since the trigger is an "after" trigger, from what I have learnt regarding "after" trigger, you would need to first INSERT the value contained in the variable opp (insert opp;) in order for Salesforce to generate an Id for that record. So, I would have thought that Line 7 would only work after opp has been inserted in the data base.

But, the above code seems to work fine, that is why I am perplexed and would like to understand how can the system know the opp.Id before the opp record has even been inserted by the apex code.

Thank you very much.
Best Answer chosen by Learning Apex (OOP)
Sergio AVSergio AV
Since its after insert, you actually do have the Id. You would not have it on the before insert.

Either way, the code is going against two of the typical best practices.
  1. NEVER put a SOQL query inside a loop.
  2. NEVER put a DML statement (insert) inside a loop.
 
trigger OwnerManager on Opportunity (after insert) {
    Map<Id,Opportunity> oppsMap = new Map<Id,Opportunity>([
                                            SELECT Id,
                                                 Owner.ManagerId
                                            FROM Opportunity
                                            WHERE Id = :opp.Id]);
    List<OpportunityTeamMember> otms = new List<OpportunityTeamMember>();
    for(Opportunity opp : Trigger.new){
        
        //Create Opportunity Team Role
        if (oppsMap.get(opp.Id).Owner.ManagerId != null) {
            OpportunityTeamMember otm = new OpportunityTeamMember();
            otm.UserId                = oppsMap.get(opp.Id).Owner.ManagerId;
            otm.OpportunityId         = opp.Id;
            otm.TeamMemberRole        = 'Sales Manager';
            otms.add(otm);
        }
    }

    insert otms;
}

Or if you actually want to get rid of the SOQL Query, since is just for a single field, you could create a formula field and use it inside the trigger, so no query needs to be made.
// Assuming your formula field api name is OwnerManagerIdAuto__c, just remove the query and replace
// oppsMap.get(opp.Id).Owner.ManagerId
// by
// opp.OwnerManagerIdAuto__c




 

All Answers

Sergio AVSergio AV
Since its after insert, you actually do have the Id. You would not have it on the before insert.

Either way, the code is going against two of the typical best practices.
  1. NEVER put a SOQL query inside a loop.
  2. NEVER put a DML statement (insert) inside a loop.
 
trigger OwnerManager on Opportunity (after insert) {
    Map<Id,Opportunity> oppsMap = new Map<Id,Opportunity>([
                                            SELECT Id,
                                                 Owner.ManagerId
                                            FROM Opportunity
                                            WHERE Id = :opp.Id]);
    List<OpportunityTeamMember> otms = new List<OpportunityTeamMember>();
    for(Opportunity opp : Trigger.new){
        
        //Create Opportunity Team Role
        if (oppsMap.get(opp.Id).Owner.ManagerId != null) {
            OpportunityTeamMember otm = new OpportunityTeamMember();
            otm.UserId                = oppsMap.get(opp.Id).Owner.ManagerId;
            otm.OpportunityId         = opp.Id;
            otm.TeamMemberRole        = 'Sales Manager';
            otms.add(otm);
        }
    }

    insert otms;
}

Or if you actually want to get rid of the SOQL Query, since is just for a single field, you could create a formula field and use it inside the trigger, so no query needs to be made.
// Assuming your formula field api name is OwnerManagerIdAuto__c, just remove the query and replace
// oppsMap.get(opp.Id).Owner.ManagerId
// by
// opp.OwnerManagerIdAuto__c




 
This was selected as the best answer
Learning Apex (OOP)Learning Apex (OOP)
Gracias/Thank you Sergio.