1

There are no errors - it just doesn't update the Asset__c field on the Asset's Account. All I can think is that I'm not initializing the Account correctly, but I can't see where the problem is. Any ideas?

Trigger UpdateAssetLookup on Asset(Before Insert)
{
    Set<Id> AccountIds = New Set<Id>();

    For(Asset Ass : Trigger.New)
    {
        AccountIds.Add(Ass.AccountId);
    }

    List<Account> AccountList = [Select Id,Asset__c from Account where id =: AccountIds];

    For(Asset AT : Trigger.New)
    {    
        For(Account ACC : AccountList)


                IF(AT.Id != NULL)
                {
                    ACC.Asset__c = AT.Id ;
                }

        }
    }  

1 Answer 1

6

It isn't working because the Asset Id field is null in the before insert context.

Records do not have Ids until after insert.

Beyond that, you're updating an Account record in your Asset trigger, but you aren't performing a DML update for those Accounts.

You can only avoid DML in triggers in before contexts on the same SObject (so in your Asset trigger, you can only avoid DML for the Asset records that caused the trigger to fire).

If you need to update other SObjects (like Account), Salesforce recommends using an after trigger.

+edit:

After taking a third look at your trigger, I think there's still more work that you need to do. Right now, you're updating the Asset__c field of each Account that you queried multiple times (meaning all of the Accounts you queried will have Asset__c set to whichever Asset record happens to be the last on in Trigger.new).

I doubt that's what you intend to have happen. You could fix things (and get rid of your nested loop) by putting the results of your Account query into a map (instead of a list), but you could completely avoid both the nested loop and your query for Accounts.

You could do this by using the following pattern (which you'll need to adjust to your particular situation).

// Declare a list to hold records that we want to update
List<OtherObject__c> myOtherObjectsToUpdate = new List<OtherObject__c>();
for(MyObject__c myObj :Trigger.new){
    // Each SObject has a constructor that allows you to specify name-value pairs
    //   for fields.
    // You can use this to set the Id field (which is otherwise read-only).
    // Doing so allows you to update a record without the need to query for it first.
    myOtherObjectsToUpdate.add(new OtherObject__c(
        Id = myObj.OtherObject__c,        // just like all other method calls, name = value pairs are separated by commas in the constructor
        someLookupField__c = myObject.Id  // you can also set other writable fields in the constructor
    ));
}

update myOtherObjectsToUpdate;
5
  • Great answer, thanks. I did try it with an after insert context too, with no change in result. It must be that I need a DML then.
    – user34868
    Commented Jun 19, 2017 at 14:19
  • 1
    @ESil Since you're trying to update an `Account, yes, you do. I took a third look through your question/code and have edited my answer to include a few more suggestions.
    – Derek F
    Commented Jun 19, 2017 at 14:43
  • Playing with this new pattern, I've run into a Invalid initial expression type error for the part where I set the new value of the lookup field (Asset__c = Asset.Id) - which I'm guessing is a problem with Asset__c being a lookup field and Asset.Id being an Id field?
    – user34868
    Commented Jun 19, 2017 at 15:54
  • @ESil lookup fields do actually store Ids, so that shouldn't be the issue. Giving the full text of the error (verbatim) may help, but I think the issue is probably in the for(MyObject__c myObj :Trigger.new) part. Trigger.new is a List<Asset> in your case, so MyObject__c should be replaced with Asset.
    – Derek F
    Commented Jun 19, 2017 at 16:06
  • That did the trick :)
    – user34868
    Commented Jun 19, 2017 at 16:11

You must log in to answer this question.