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
Thakkar ParthThakkar Parth 

Error: Compile Error: Field expression not allowed for generic SObject

I'm getting an error and not able to find solution . I'm trying to use best practice of trigger using trigger handler . Following is what I did uptil now . Anyone please help me to structure or help me with modification .Thanks in advance.



===Trigger===

trigger OpportunityTrigger on Opportunity (after update) {
   new OpportunityTriggerHandler().run();
}

=== Trigger Handler class ===
public virtual class TriggerHandler {

  public TriggerHandler() { }
  
  // main method that will be called during execution
  public void run() {

     // dispatch to the correct handler method
      if(Trigger.isAfter && Trigger.isUpdate) {
      this.afterUpdate();
    } 
  }

  // context-specific methods for override
  protected virtual void afterUpdate(){}
  protected virtual void afterDelete(){}
    
  // exception class
  public class TriggerHandlerException extends Exception {}

}

== OpportunityTriggerHancler Class== 

I'm getting error in this class .
public class OpportunityTriggerHandler extends TriggerHandler {

   List<Task> tasks = new List<Task>();
   List<Opportunity> Opps = Trigger.new;
   Map <Id, String> oppsOwner = new Map <Id, String> ();
   
   public OpportunityTriggerHandler() {}
  
   protected override void afterUpdate()
  {
    for (Opportunity opp : trigger.new)
    {
        // Check if the StageName has been changed
        if (opp.StageName != trigger.oldMap.get(opp.Id).StageName)
        {
            // get the owner ID's that have been affected
            oppsOwner.put(opp.ownerId, null);
        }
    }

    // Map the owner ID to it's email address
    for (User owner : [SELECT Id, Email FROM User WHERE Id = :oppsOwner.keySet()])
    {
        oppsOwner.put(owner.Id, owner.Email);
    }
        
  }
   
  }


Best Answer chosen by Thakkar Parth
Ankit AroraAnkit Arora
Problem is with the type casting, try this :

public class OpportunityTriggerHandler extends TriggerHandler {

   List<Task> tasks = new List<Task>();
   List<Opportunity> Opps = Trigger.new;
   Map <Id, String> oppsOwner = new Map <Id, String> ();
   
   public OpportunityTriggerHandler() {}
  
   protected override void afterUpdate()
  {
    for (sObject oppTemp : trigger.new)
    {
        Opportunity opp = (Opportunity)oppTemp ;
        // Check if the StageName has been changed
        Opportunity oldOpp = (Opportunity)trigger.oldMap.get(opp.Id) ;
        if (opp.StageName != oldOpp.StageName)
        {
            // get the owner ID's that have been affected
            oppsOwner.put(opp.ownerId, null);
        }
    }

    // Map the owner ID to it's email address
    for (User owner : [SELECT Id, Email FROM User WHERE Id = :oppsOwner.keySet()])
    {
        oppsOwner.put(owner.Id, owner.Email);
    }
        
  }
   
  }


All Answers

Prem_PalPrem_Pal
Try type casting,
List<Opportunity> Opps = (List<Opportunity>) Trigger.new;


pbattissonpbattisson
As mentioned above you can try casting, this error is when you try to retrieve a field that is not an object standard field (i.e. those fields every object has  - Id, CreatedDate etc.). You could also do 
if(opp.get('StageName') != trigger.oldMap.get(opp.Id).get('StageName'))
on line 14 and this should solve the probelm.
Ankit AroraAnkit Arora
Problem is with the type casting, try this :

public class OpportunityTriggerHandler extends TriggerHandler {

   List<Task> tasks = new List<Task>();
   List<Opportunity> Opps = Trigger.new;
   Map <Id, String> oppsOwner = new Map <Id, String> ();
   
   public OpportunityTriggerHandler() {}
  
   protected override void afterUpdate()
  {
    for (sObject oppTemp : trigger.new)
    {
        Opportunity opp = (Opportunity)oppTemp ;
        // Check if the StageName has been changed
        Opportunity oldOpp = (Opportunity)trigger.oldMap.get(opp.Id) ;
        if (opp.StageName != oldOpp.StageName)
        {
            // get the owner ID's that have been affected
            oppsOwner.put(opp.ownerId, null);
        }
    }

    // Map the owner ID to it's email address
    for (User owner : [SELECT Id, Email FROM User WHERE Id = :oppsOwner.keySet()])
    {
        oppsOwner.put(owner.Id, owner.Email);
    }
        
  }
   
  }


This was selected as the best answer
Thakkar ParthThakkar Parth
Thanks all,but stucked once again with new requirement and with the same error . The error is at line 10

public class opportunityTriggerHandler2
{
  List<Task> tasks = new List<Task>();
   List<Opportunity> Opps = (List<Opportunity>)Trigger.new;
  
   public void createTask()
  {  
    for (Opportunity Opp :  Opps)
   {
     if(opp.StageName == 'Closed Won' && trigger.oldMap.get(opp.Id).StageName != opp.StageName) {
     
     Task tsk = new Task(whatID = Opp.ID, Ownerid = Opp.OwnerId);
     tasks.add(tsk); 
    }  
   } 
   insert tasks;
  }
}

I did type casting and still no luck .
pbattissonpbattisson
You have only casted the first opportunity - look at Ankit's code and modify yours to have line 10 as something like :
Opportunity oldOpp = (Opportunity)trigger.oldMap.get(opp.Id) ;
if (opp.StageName != oldOpp.StageName)

The opportunity in trigger.oldmap is also returning as an SObject and needs casting correctly.
Ankit AroraAnkit Arora
Marc, as Paul said please use the exact code as I think you missed using this 

for (sObject oppTemp : trigger.new)

and still using

for (Opportunity Opp :  Opps)

Would request you to use my complete code and then do your modifications.
Thakkar ParthThakkar Parth
Thanks Ankit , very informative for me . @pBattison, thanks for the conceptual understanding as to why this error occurs. Thans to Prem Pal as well.