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
JSchneiderJSchneider 

Update Lookup Record from isUpdate Trigger

trigger Sales_Invoice_Custom_Trigger on c2g__codaInvoice__c (before insert, before update) {
    // if this SIN is getting inserted
    if( Trigger.isInsert ) {
        for(c2g__codaInvoice__c SIN : Trigger.new)
        {}
    }
    // if this SIN is getting updated
    if( Trigger.isUpdate ) {
        for(c2g__codaInvoice__c SIN : Trigger.new)
            //check that it has a Sales Order*
            if(SIN.Sales_Order__c != null)
        {
            //get the SIN Outstanding Value
            decimal SINov = SIN.c2g__OutstandingValue__c;
            //query and update the Sales Order*
            Sales_Order__c SalesO = [SELECT Id FROM Sales_Order__c WHERE Id = :SIN.Sales_Order__r].Id;
            SalesO.Outstanding_Value__c = SINov;
        }
    }
}

I am having a problem with the acutal update of the Sales_Order__c record.  Any advice is appreciated, still learning APEX.
William TranWilliam Tran
Where are you updating the sales order?

Try using:  update SalesO;


As a common practice, if your question is answered, please choose 1 best answer. 
But you can give every answer a thumb up if that answer is helpful to you. 

Thanks
Chris SweetChris Sweet
Hi JSchneider,

Typically, in a before trigger you would not need to us a DML statement (e.g. insert, update), but because you're altering a different object (Sales_Order__c) rather than the c2g__codaInvoice__c records that fired the trigger, the DML is necessary, as William states above.

You should be careful with this trigger as it breaks a cardinal rule of Apex: Don't put DML or SOQL inside a FOR loop. You're better off gathering a list of Sales_Order__r ID's and using that list in a separate SOQL outside of the for loop.

-Chris
JSchneiderJSchneider
I've added the update SalesO line, however the issue I am running into is :
16|   Invalid bind expression type of Sales_Order__c for column of type Id

And I've heard of this before but never know what the risks of putting a DML or SOQL inside a FOR loop are?
Neetu_BansalNeetu_Bansal
Hi JSchneider,

As you are updating a different object, so I would suggest to do that in after trigger, and using DML or SOQL in for loop will results in salesforce limits exceptions, when performing bulk insertion/updation/deletion. In your code, your are getting only the Id, that's why you are getting exception. Use the below code:
trigger Sales_Invoice_Custom_Trigger on c2g__codaInvoice__c( before insert, after update )
{
    // if this SIN is getting inserted
    if( trigger.isInsert )
	{
        for(c2g__codaInvoice__c SIN : trigger.new)
        {
		}
    }
	
    // if this SIN is getting updated
    if( trigger.isUpdate )
	{
		List<Sales_Order__c> salesOrders = new List<Sales_Order__c>();
		
		for( c2g__codaInvoice__c SIN : trigger.new )
		{
            //check that it has a Sales Order*
            if( SIN.Sales_Order__c != null )
			{
				//get the SIN Outstanding Value
				decimal SINov = SIN.c2g__OutstandingValue__c;
				
				//query and update the Sales Order*
				Sales_Order__c SalesO = new Sales_Order__c( Id = SIN.Sales_Order__c, Outstanding_Value__c = SINov );
				salesOrders.add( SalesO );
			}
		}
		
		if( salesOrders.size() > 0 )
			update salesOrders;
    }
}
Let me know, if you need any other help.

Thanks,
Neetu
Chris SweetChris Sweet
To answer your question, the risks are around limits put in place (and in this case, rightly so) by SFDC. Running a query on every single iteration of a list is extremely inefficient and even worse for DML operations. It's very possible you may not even hit the limit right now (100 SOQL queries in a single call) if you're not running this against many records, but in my personal experience these are some of the easiest limits to reach if you're not careful.

Think of how the flow would be for 200 records. For every iteration you would check if statement, do the SOQL query and apply the DML (after this DML, other triggers may run, which may fire other DML and SOQL). Taking the DML and SOQL out of the loop turns potentially 200 queries (or more) and 200 DMLs into 1 query (or none at all if you look at Neetu's code above) and 1 DML. The idea around all of this is that SFDC's servers aren't constantly being slammed by unnecessary round trips.
ram4SFDCram4SFDC
As indicated by others you should not be using a SOQL inside a for loop. Salesforce recommends use of List and Maps.
Also in you code below you were trying to query Id field value and assign to Sales Order object which is why salesorce throws an error.
Sales_Order__c SalesO = [SELECT Id FROM Sales_Order__c WHERE Id = :SIN.Sales_Order__r].Id;

Since you are trying to udpate another and you have the Id of those records, you can simply instantiate the custom object and udpate the value.
trigger Sales_Invoice_Custom_Trigger on c2g__codaInvoice__c (before insert, before update) {
    // if this SIN is getting inserted
    if( Trigger.isInsert ) {
        for(c2g__codaInvoice__c SIN : Trigger.new)
        {}
    }
    // if this SIN is getting updated
	// Create a lsit of sales order to update
	List<Sales_Order__c> lst_salesOrder = new List<Sales_Order__c>();
    if( Trigger.isUpdate ) {
        for(c2g__codaInvoice__c SIN : Trigger.new)
            //check that it has a Sales Order*
            if(SIN.Sales_Order__c != null)
        {
            //get the SIN Outstanding Value
            decimal SINov = SIN.c2g__OutstandingValue__c;
            lst_salesOrder.add(new Sales_Order__c(Id=SIN.Sales_Order__c,Outstanding_Value__c=SINov));
        }
		if(lst_salesOrder.size()>0)
				update lst_salesOrder;
    }
}