+ Start a Discussion
Learning Apex (OOP)Learning Apex (OOP) 

Why is SOQL query necessary here?

Hello, I need to understand WHY my first code below (b) does NOT work.

(a) Here is the functional requirement: when creating a new Case, I want the related Contact (parent) to have its Owner updated with the Case's CreatedBy user, in other words, the Case's CreatedBy will be used to update the Contact's Owner.

(b) Here is the code that does NOT work
trigger CaseContactOwner on Case (after insert){
    for(Case myCase:Trigger.new){
        if(myCase.ContactId != null){
            myCase.Contact.OwnerId = myCase.CreatedById;
        }
    } 
}

(c) Here is the solution (the code that DOES works fine):
trigger CaseContactOwner on Case (after insert) {
    for(Case myCase:Trigger.new){
        // Make sure the Case has an Contact
        if(myCase.ContactId != null){
            // Find the contact for updating
            Contact myContact = [SELECT Id
                                   FROM Contact
                                   WHERE Id = :myCase.ContactId];
            // Update the Contact
            myContact.OwnerId = myCase.CreatedById;
        }
    }
}

My question is:

As the trigger is an "after insert" trigger, I would have thought that Line 4 (of my first code b) would work fine:
myCase.Contact.OwnerId = myCase.CreatedById;
//this would assign the value in CreatedById on my new Case to the Owner of the associated Contact of my Case.

But that does NOT work and I do not understand why.

The solution seem to be (c) where I have to query on the table Contact and store the resulting record on a SObject variable (myContact) which I eventually use to reference the Owner of the Contact.
Is it really necessary to do all this query?

Thank you very much.
Suraj TripathiSuraj Tripathi

Hi,

The reason is that because we receive only ID via trigger. If you want access other fields then you have to write a SOQL query.

Regards,

Suraj
 

Learning Apex (OOP)Learning Apex (OOP)
Hi Suraj,

When you say "we receive on ID via trigger", what do you exactly mean?

Are you saying that Trigger.new only provides the Id of the Case?

How can I know what does Trigger.new exactly provides as fields?

Thank you.
Suraj TripathiSuraj Tripathi
yes, In trigger we only get ID of that object's record. So in order to get some other fields other then ID, we need to do query to get the other fields.
Kai Herng LauKai Herng Lau
Hi,

I don't think both of you code is working because you are using after insert and without DML action salesforce will not perform the update function for you. Another thing in your second example (c), the SOQL query is performed inside the for loop is very dangerous to hit into Query limit if you perform bulk update or insert in case object.

What Suraj mean is the Trigger.new's Contact is just the Id not the contact object

My suggestion is:
 
trigger CaseContactOwner on Case (after insert){
    List<Contact> updateContacts = new List<Contact>();
    for(Case myCase:Trigger.new){
        if(myCase.ContactId != null){
            
            Contact newCont = new Contact();
            newCont.Id = myCase.ContactId;
            newCont.OwnerId = myCase.CreatedById;
            
            updateContacts.add(newCont);
        }
    } 
    update updateContacts;
}

Hope this is help
Learning Apex (OOP)Learning Apex (OOP)
Hi Suraj and Kai,

Thank you to both of you.
I realise that I forgot the DML statement on my last code (c).
And the way you substitute the SOQL query inside the for loop by a List<> and DML statement ouside the For loop makes sense to me.
Thank you.

The only remaining doubt is regarding the fields contained/included in Trigger.new.
Suraj says that only the ID field is included in Trigger.new but, if the trigger was for example on Account or Contact or any custom object, I think that Trigger.new would include all the base fields of such object (i.e. Standard fields plus Custom fields, but NOT fields of related objects).

I haven't got a cristal clear source of information to know exactly what fields are included in Trigger.new (when using it as a list utilised in a For loop in a trigger).

Do you have a good source of information explaining what fields are included in trigger.new for each possible object I could trigger? (perhaps, Case would be the only object where only the ID of the Case is included in Trigger.New)

Thank you very much.
srlawr uksrlawr uk
That's not been reported correctly. 

Any field referenced directly on an object used in a trigger is present. So on your trigger for Case... and field referenced directly (that is, using a dot notation - not using dynamic stuff etc.) will be loaded up for you.

Don't ask how it works, it's some under-the-hood magic lazy loading thing Salesforce does for you.

What isn't ever loaded are fields over a relationship (so if your trigger on Case cannot lazy load Case.Contact.FirstName) 
Learning Apex (OOP)Learning Apex (OOP)
Hi srlawr uk,

Thank you for trying to explain it to me. Unfortunately, I think I am not fully getting everything you are trying to tell me. Could you possibly write a few examples/scenarios for me to understand Salesforce's rule?

My understanding from what you are saying is:
  • If my trigger is on the object Case (as an example), when using trigger.new in a "for" loop (as in both codes above), I should be able to reference ANY field from the Case. This would mean that I could reference fields (in my apex code) such as AccountId, CaseNumber, ContactId, plus any other Custom fields and/or System fields, RIGHT? Is this correct?
  • Based on the same trigger on Case, I could NOT reference in my apex code any field from any RELATED object to the Case, i.e. I could NOT reference in my apex trigger (on Case) any field on the Contact or on the Account related to such Case, RIGHT? Is this correct?
Please, let me know if my interpretation is correct or not and also, if you have any official source of information backing up this theory, that would be great.

Thank you very much.