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
JJamesJJames 

Updating a Lookup(user) field with OpportunityContactRole in Trigger

I am trying to take whoever the primary user is in an opportunity's contact roles and populate a Lookup(user) field with this person but need a little help.  This is what I have but i am missing some understanding of contactrole and user's id relationship.  How would I accomplish this?
 
trigger UpdateOpportunityContact on Opportunity (after update, after insert) {
    List<OpportunityContactRole> contactRoles = new List<OpportunityContactRole>();
    
    for( Opportunity acc : [ Select Id, (SELECT OpportunityId,IsPrimary,ContactId  FROM OpportunityContactRoles) FROM Opportunity ])
    {
        contactRoles.addALL(acc.OpportunityContactRoles);
    }
    for(Opportunity opp : trigger.new)
    {
    for(OpportunityContactRole role : contactRoles)
    {
        if(role.IsPrimary)
        {
            opp.Primary_Contact__c = new User(ContactId = role.ContactId);
            upsert opp.Primary_Contact__c;
        }
    }
    }

}

 
Best Answer chosen by JJames
Vishal Negandhi 16Vishal Negandhi 16

Some feedback on your code before we move to the solution:

Why do you query all Opportunities in your system here?
for( Opportunity acc : [ Select Id, (SELECTOpportunityId,IsPrimary,ContactId  FROMOpportunityContactRoles) FROM Opportunity ])
Just consider a scenario where you've millions of Opportunities, your code will stop working here itself because you haven't applied any filter.

Here, opp.Primary_Contact__c = new User(ContactId =role.ContactId); : you're referring a User in a lookup to Contact. This is incorrect. 
It should ideally be;
opp.Primary_Contact__c = new Contact(Id = role.ContactId);

And also this line : upsert opp.Primary_Contact__c;
This shouldn't be in a FOR loop : as a golden rule to make a trigger bulk handled we are not supposed to write any SOQLs or DMLs inside a for loop. 
Secondly, you're upserting a record not a field. 
So your statement should have been
upsert opp;
 

All Answers

Vishal Negandhi 16Vishal Negandhi 16

Some feedback on your code before we move to the solution:

Why do you query all Opportunities in your system here?
for( Opportunity acc : [ Select Id, (SELECTOpportunityId,IsPrimary,ContactId  FROMOpportunityContactRoles) FROM Opportunity ])
Just consider a scenario where you've millions of Opportunities, your code will stop working here itself because you haven't applied any filter.

Here, opp.Primary_Contact__c = new User(ContactId =role.ContactId); : you're referring a User in a lookup to Contact. This is incorrect. 
It should ideally be;
opp.Primary_Contact__c = new Contact(Id = role.ContactId);

And also this line : upsert opp.Primary_Contact__c;
This shouldn't be in a FOR loop : as a golden rule to make a trigger bulk handled we are not supposed to write any SOQLs or DMLs inside a for loop. 
Secondly, you're upserting a record not a field. 
So your statement should have been
upsert opp;
 

This was selected as the best answer
JJamesJJames
Thank you for sharing your knowledge.  After making the changes you suggested and changing the primary contact equal to an id instead of a contact it now populates correctly.
I have a question though, I was trying to do this through a subquery and it didn't return any results, can you see what I am doing wrong in the query?  I am trying to learn as much as possible (i realize it isn't idea with creating a list for a single object and referring to the single item in the list array)  :

trigger UpdateOpportunityContact on Opportunity (before update, before insert) {
    List<OpportunityContactRole> contactRoles = new List<OpportunityContactRole>();
    
    for( Opportunity acc : [ Select Id, (SELECT Id,OpportunityId,IsPrimary,ContactId FROM OpportunityContactRoles WHERE IsPrimary=true) FROM Opportunity where Id IN: trigger.new])
    {
        contactRoles.addALL(acc.OpportunityContactRoles);
        if(contactRoles.size() > 0)
        {
            contactRoles.addALL(acc.OpportunityContactRoles);
            for(User pUser : [Select id, Name From User WHERE id=:contactRoles[0].id])
            {
                acc.Primary_Contact__c = pUser.id;
            }
        }
    }
}

Again thanks for your help!