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
DekorDekor 

Apex trigger update help needed!

Hello,

 

I have created a trigger that runs a class to update the account on an asset when an inactive tick box is ticked.

 

Here is my class:

 

public with sharing class Inactive_asset_class {

   public static void Inactive_asset(Asset[] cont){

      ASSET a = [select asset.AccountId FROM ASSET where Inactive__c=true ];
      a.Accountid = '0012000000oX453';
      update a.account;
   }
}

 

Here is my trigger:

 

trigger inactive_asset on Asset (after update){
    Inactive_asset_class.Inactive_asset(Trigger.new);

}

 

Here is my test:

@isTest
private class InactiveTriggerTest {

    static testMethod void myUnitTest() {
       
       //create a test asset
       
       Asset test_asset = new Asset(id='02i2000000KU6mR',accountid='0012000000foauZ',name='0012000000foauZ',Asset_Tag__c = '18668',Inactive__c=false);
       
       test_asset.Inactive__c=true;
       UPDATE (test_asset);
       

  
      }
}

 

 

Unfortunately the trigger is failing to deploy with this failure, any ideas?  I just can't suss this out!

 

Run Failures:
  InactiveTriggerTest.myUnitTest System.DmlException: Update failed. First exception on row 0 with id 02i2000000KU6mRAAT; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, inactive_asset: execution of AfterUpdate

caused by: System.NullPointerException: Attempt to de-reference a null object

Class.Inactive_asset_class.Inactive_asset: line 7, column 14
Trigger.inactive_asset: line 2, column 5: []

 

Best Answer chosen by Admin (Salesforce Developers) 
grigri9grigri9

You need to add that conditional inside the for loop

 

public with sharing class Inactive_asset_class {

   public static void Inactive_asset(Asset[] cont){
      //this way you do not have a hard-coded accountid
      Account inactiveacc = [select ID from account where name='Inactive'];
      for(Asset a : cont)
      {
          //no update required because this a before trigger

          if(a.inactive__c) a.Accountid = inactiveacc.id;
      } 
   }
}

 

All Answers

grigri9grigri9

You need to update the sobject not the field. Just change your code to the following.

 

public with sharing class Inactive_asset_class {

   public static void Inactive_asset(Asset[] cont){

      ASSET a = [select asset.AccountId FROM ASSET where Inactive__c=true ];
      a.Accountid = '0012000000oX453';
      update a;
   }
}

 

DekorDekor

I get a more complex error now when uploading the trigger:

 

caused by: System.DmlException: Update failed. First exception on row 0 with id 02i2000000KU6mRAAT; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, inactive_asset: maximum trigger depth exceeded
Asset trigger event AfterUpdate for [02i2000000KU6mR]
Asset trigger event AfterUpdate for [02i2000000KU6mR]
Asset trigger event AfterUpdate for [02i2000000KU6mR]
Asset trigger event AfterUpdate for [02i2000000KU6mR]
Asset trigger event AfterUpdate for [02i2000000KU6mR]
Asset trigger event AfterUpdate for [02i2000000KU6mR]
Asset trigger event AfterUpdate for [02i2000000KU6mR]
Asset trigger event AfterUpdate for [02i2000000KU6mR]
Asset trigger event AfterUpdate for [02i2000000KU6mR]
Asset trigger event AfterUpdate for [02i2000000KU6mR]
Asset trigger event AfterUpdate for [02i2000000KU6mR]
Asset trigger event AfterUpdate for [02i2000000KU6mR]
Asset trigger event AfterUpdate for [02i2000000KU6mR]
Asset trigger event AfterUpdate for [02i2000000KU6mR]
Asset trigger event AfterUpdate for [02i2000000KU6mR]
Asset trigger event AfterUpdate for [02i2000000KU6mR]: []

Class.Inactive_asset_class.Inactive_asset: line 7, column 7
Trigger.inactive_asset: line 2, column 5: []

grigri9grigri9

Actually, reading over your business requirements you can do this in a much simpler fashion. When an asset is marked as 'inactive' you want to move it over to a special inactive account?

 

Do it the following way:

 

 

trigger inactive_asset on Asset (before update){
    Inactive_asset_class.Inactive_asset(Trigger.new);

}

 

public with sharing class Inactive_asset_class {

   public static void Inactive_asset(Asset[] cont){
      //this way you do not have a hard-coded accountid
      Account inactiveacc = [select ID from account where name='Inactive'];
      for(Asset a : cont)
      {
          //no update required because this a before trigger
          a.Accountid = inactiveacc.id;
      } 
   }
}

 

grigri9grigri9

The reason you are getting that error is because you are performing an update inside an update trigger so you are getting stuck in an infinite loop. I re-wrote this so that you don't need to perform a dml operation in the post above.

 

However, if you ever need to do that the way to go is a static boolean in your class that checks whether or not you have already run the class.

Chamil MadusankaChamil Madusanka

Hi,

Your inactive_asset trigger fire after update the Asset object and call the Inactive_asset method. Then the method update the Asset object instance. Therefore the method will be fired from the method.

You're essentially in an infinite loop, and Apex kicks you out. I'm not sure what you're trying to do with your code, but if you have a trigger that is modifying the same object that you're triggering on, you have to be careful not to get into these kinds of loops.

If a reply to a post answers your question or resolves your problem, please mark it as the solution to the post so that others may benefit.


DekorDekor

Thank you so much for your help.  This is deployed and working.

 

One thing I am having trouble understanding is where within the code you have provided does it say to perform this class if the inactive checkbox is ticked?  Just so I have a better understanding myself.

DekorDekor

Ah, this is now triggering whenever an asset is updated!  Help!

DekorDekor

Ok I've managed to make it inactive for now.  Can't fathom how to add my criteria to the trigger!

grigri9grigri9

You need to add that conditional inside the for loop

 

public with sharing class Inactive_asset_class {

   public static void Inactive_asset(Asset[] cont){
      //this way you do not have a hard-coded accountid
      Account inactiveacc = [select ID from account where name='Inactive'];
      for(Asset a : cont)
      {
          //no update required because this a before trigger

          if(a.inactive__c) a.Accountid = inactiveacc.id;
      } 
   }
}

 

This was selected as the best answer
DekorDekor

Can't deploy trigger now:

 

# Test Results:

Run Failures:
  InactiveTriggerTest.myUnitTest System.DmlException: Update failed. First exception on row 0 with id 02i2000000KU6mRAAT; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, inactive_asset: execution of BeforeUpdate

caused by: System.QueryException: List has no rows for assignment to SObject

Class.Inactive_asset_class.Inactive_asset: line 5, column 29
Trigger.inactive_asset: line 2, column 5: []

grigri9grigri9

That error message is saying that the account query on line 5 of Class.Inactive_asset_class.Inactive_asset is not returning any rows. Does your 'inactive' account exist on both sandbox and production?

Chamil MadusankaChamil Madusanka

Hi,

 

Do following changes.

 

public with sharing class Inactive_asset_class {

public static void Inactive_asset(Asset[] cont){
//this way you do not have a hard-coded accountid
Account[] inactiveacc = [select ID from account where name='Inactive'];
if(inactiveacc.size() > 0)
{
for(Asset a : cont)
{
//no update required because this a before trigger

if(a.inactive__c) a.Accountid = inactiveacc[0].id;
}
}

}
}

If a reply to a post answers your question or resolves your problem, please mark it as the solution to the post so that others may benefit.

DekorDekor

Gregory, it seemed the class hadn't updated with correct account name.  It was still inactive but account i used is called DELETED ASSETS.  Had to redeploy it.  Now working.  Thank you for your help.