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
Abilash Kosigi 8Abilash Kosigi 8 

Account Clone Trigger (with Dynamic SOQL & Clone method)

<This post is in continuation to older posts>

Hi,

I have tried a bit sophisticated trigger with a dyanamic DML Query and Clone method of SObject class. I am almost there except this error which comes when a new account is added. Can anyone of you dig out and let me know.

The error is

Review all error messages below to correct your data.
Apex trigger accountClone caused an unexpected exception, contact your administrator: accountClone: execution of AfterInsert caused by: System.QueryException: Variable does not exist: Trigger.new:


Trigger:

trigger accountClone on Account (after insert) {
Account[] accSave = new Account[] {};

if(CheckRecursiveTrigger.runOnce())
{
Account theClone= new Account();

Account A=new Account();

String DMLQuery;
        DMLQuery = 'Select ';
Map<String, Schema.SObjectField> fieldsMap = Schema.SObjectType.Account.fields.getMap();
for (Schema.SObjectField field : fieldsMap.values())
     {
      DMLQuery += field.getDescribe().getName() + ',';
      System.debug(field.getDescribe().getName());
     }
        DMLQuery = DMLQuery.substring(0, DMLQuery.length() -1);
DMLQuery += ' from Account where Id IN : Trigger.new';
          
      
    A = Database.query(DMLQuery);


  theClone =  A.clone(false,true,false,true);

accSave.add(theClone);
}

insert accSave; 


}
shiv@SFDCshiv@SFDC
Might be you are getting errors becuase of composite fields. For example BillingAddress, ShippingAddress. When we call describe for these field it will return API name ShippingAddress, ShippingAddress. but as we know we can not make query for these fields directly. we have to make like this billing city, zip etc.....

if this is the issue you can check it easly :

You modiy this code like this way to check the issue
for (Schema.SObjectField field : fieldsMap.values())
     {
     // If the data type is not address than only it add to account
    if(field.getDescribe().getType() != 'Address' )
      {
      DMLQuery += field.getDescribe().getName() + ',';
      }
      System.debug(field.getDescribe().getName());
     }
Since you are inserting records we have to avoid read only fields and formula fields. So our final code of block can be like this
for (Schema.SObjectField field : fieldsMap.values())
     {
     // If the data type is not address than only it add to account - avoid read only fields
    if(field.getDescribe().getType() != 'Address' && field.getDescribe().isCreateable() == true && field.getDescribe().isCalculated() == false)
      {
      DMLQuery += field.getDescribe().getName() + ',';
      }
      System.debug(field.getDescribe().getName());
     }
Other code will be same. check with above changes either it works fine or not. If this is the solution for your problem mark it as solution.


Abilash Kosigi 8Abilash Kosigi 8
I found a solution to this problem minutes after posting to this thread. The following code works perfect. The guys who posted earlier can use this.

Trigger:

trigger accountClone on Account (after insert) {
Account[] accSave = new Account[] {};

if(CheckRecursiveTrigger.runOnce())
{
Account theClone= new Account();
Account k = [Select Id from Account where Id IN : trigger.new];
String idVar = k.Id;
Account A=new Account();
String DMLQuery;

DMLQuery = 'Select ';
Map<String, Schema.SObjectField> fieldsMap = Schema.SObjectType.Account.fields.getMap();

    for (Schema.SObjectField field : fieldsMap.values())
       {
        DMLQuery += field.getDescribe().getName() + ',';
        System.debug(field.getDescribe().getName());
       }
       
DMLQuery = DMLQuery.substring(0, DMLQuery.length() -1); 
DMLQuery += ' from Account where Id = :idVar ';
           
       
    A = Database.query(DMLQuery);

  theClone =  A.clone(false,true,false,true);

accSave.add(theClone);
}

insert accSave;   
}




CheckRecursiveTrigger Class:

public class CheckRecursiveTrigger {
    private static boolean run = true;
    public static boolean runOnce(){
        if (run)
        {
            run=false;
            return true;
        }
        else
        {
            return false;
        }
    }

}


shiv@SFDCshiv@SFDC
what was the problem ?
shiv@SFDCshiv@SFDC
Means where we were doing mistake ?
Abilash Kosigi 8Abilash Kosigi 8
We cannot call Trigger.new variable directly in Database.query statement. Hence, I have written this statement

Account k = [Select Id from Account where Id IN : trigger.new];
String idVar = k.Id;

Here, I first fetched the result to Account object and then assigned 'Id' value to String variable.