+ Start a Discussion
alexjalexj 

System.FinalException: Record is read-only

Hi

I have created an apex class to verify if there is a new account isn't on the lead and if it's the case, I retrieve the value of the lead to update my account.

But when I try an exemple, I have an error : System.FinalException: Record is read-only

 

My apex class is :

//mise à jour de compte si doublons

global class VerifNoLead implements  Database.Batchable<sObject> {

global final String query;
global final Account compte;

global VerifNoLead (String q, Account ld)
{
   query = q;
   compte= ld;
}

global Database.QueryLocator start(Database.BatchableContext BC){

   return Database.getQueryLocator(query);
}

global void execute(Database.BatchableContext BC, List<sObject> scope){
        for(sObject s : scope){
            Lead leadO = (Lead)s; 
            //champs identification du compte (non modifiable)
            if(leadO.Salutation != null){compte.Salutation = leadO.Salutation;}
            System.debug(compte.Salutation);
            if(leadO.FirstName != null){compte.FirstName = leadO.FirstName;}
            if(leadO.LastName != null){compte.LastName = leadO.LastName;}
            
            compte.PersonLeadSource = leadO.LeadSource;            
         
            //information sur l'adresse. Si un est modifié, tous le sont
            if(compte.PersonMailingStreet ==null && compte.PersonMailingCity ==null && compte.PersonMailingPostalCode ==null && compte.PersonMailingCountry ==null && compte.PersonMailingState ==null)
            {
                compte.PersonMailingStreet = leadO.Street;
                compte.PersonMailingCity = leadO.City ;
                compte.PersonMailingPostalCode = leadO.PostalCode;
                compte.PersonMailingCountry = leadO.Country;
                compte.PersonMailingState = leadO.State ;
            }

            if(compte.PersonHomePhone ==null){compte.PersonHomePhone = leadO.Phone ;}
            if(compte.PersonMobilePhone ==null){compte.PersonMobilePhone =  leadO.Telephone_portable__c ;}          
            if(compte.Rating ==null){compte.Rating = leadO.Rating ;}
            if(compte.Type_d_utilisation__c ==null){compte.Type_d_utilisation__c = leadO.Type_d_utilisation__c ;}        
          
            //champ relatif à la newsletter
             if(compte.Inscription_la_newsletter__c == false && compte.D_sinscription_la_newsletter__c == false){
                if(leadO.Inscription_la_newsletter__c == true){
                    compte.Inscription_la_newsletter__c = true;
                    compte.Date_d_inscription_la_newsletter__c = leadO.Date_d_inscription_la_newsletter__c;
                    compte.D_sinscription_la_newsletter__c = leadO.D_sinscription_la_newsletter__c;
                    compte.Date_de_d_sinscription_la_newsletter__c = leadO.Date_de_d_sinscription_la_newsletter__c;
                }
            }
            

//System.debug(compte.Id);
            if(compte.Id != null){update compte;System.debug('mise à jour ok');
            }
            else {System.debug ('erreur compte');}
            if(leadO.Id != null){delete leadO;
            System.debug('leadO.id !=null');}
            else{System.debug('erreur leadO');}
            }
}



global void finish(Database.BatchableContext BC){

        System.debug('fini');
       
}

public static testmethod void testVerifNoLead (){
    List <Lead> ld = new List<Lead>();
    for(integer i = 0; i<2; i++){
        Lead l = new Lead(Adresse_mail__c='test'+i+'@mail.com',LastName='test', Inscription_la_newsletter__c =true);
        ld.add(l);
    }
    insert ld;


   
     Test.startTest() ;

     Account lnew = new Account(
            Salutation = 'M.',
            FirstName ='Hélène',
            LastName = 'test',
            Adresse_mail__c = 'test1@mail.com',
            PersonLeadSource = 'Newsletter',
           // Origine_connaissance_Kiwatch__c ='',
            Numero_client__c = 0,
            /*accepte_jeux__c = true,
            Date_inscription_au_jeu__c = ,
            Email_parr__c = 'h.broussin@kiwatch.com',
            Email_parrainage_2__c = '',
            Email_parrainage_3__c = '',
            Email_parrainage_4__c = '',
            Email_parrainage_5__c = '',*/
         //   PersonMailingStreet = '',//'39, rue des étoiles',
           // PersonMailingCity = '',//'laval',
         //   PersonMailingState = '',//'pays de loire',
          //  PersonMailingPostalCode = '',//'53000',
          //  PersonMailingCountry = '',//'france',
            PersonHomePhone = '0900000000',
            PersonMobilePhone = '070809101112',
            Rating = 'Froid',
           // Date_d_inscription_la_newsletter__c = '29/05/2012',
           // Date_de_d_sinscription_la_newsletter__c = '',
            Inscription_la_newsletter__c = false,
            D_sinscription_la_newsletter__c = false,
            Raison_de_la_d_sinscription__c = '',
            /*locataire__c = true,
            proprietaire__c = false,
            alarme__c = false,
            videosurveillance__c = false,
            alarme_et_videosurveillance__c = false,
            pas_de_systeme__c = true,*/
            Type_d_utilisation__c = 'Pro',
            demande__c = '',
            Demande_contact__c = '',
            Objet_demande__c = '',
            //Date_d_abonnement__c,
            //Date_fin_de_contrat__c,
            Raison_fin_de_contrat__c ='',
            //Date_de_l_abonnement_actuel__c,
            Abonnement__c='Pro');
              
        String query = 'SELECT  Salutation, FirstName , Adresse_mail__c, LastName, Num_ro_piste__c, LeadSource, Origine_connaissance_Kiwatch__c, Client__c, D_sinscription_la_newsletter__c, Inscription_la_newsletter__c, Raison_de_la_d_sinscription__c, Date_de_d_sinscription_la_newsletter__c, Date_d_inscription_la_newsletter__c, Street, City, State, Country, PostalCode, Phone, Telephone_portable__c    FROM Lead WHERE Adresse_mail__c=\'' + lnew.Adresse_mail__c + '\'  LIMIT 2';

       VerifNoLead batchApex = new VerifNoLead(query, lnew );
       ID batchprocessid = Database.executeBatch(batchApex);
   
       Test.StopTest();
 }
      
       
}

 and my trigger :

trigger RechercheDoubleCompte on Account(after insert) {
    for (Account a : Trigger.new) {   
                   
     String query = 'SELECT Salutation, FirstName , Adresse_mail__c, LastName, Numero_client__c, PersonLeadSource, D_sinscription_la_newsletter__c, Inscription_la_newsletter__c, Raison_de_la_d_sinscription__c, Date_de_d_sinscription_la_newsletter__c, Date_d_inscription_la_newsletter__c   FROM Account WHERE Adresse_mail__c=\'' + a.Adresse_mail__c + '\' AND   Id!=\'' + a.Id + '\' LIMIT 100';
     String query2 = 'SELECT  Salutation, FirstName , Adresse_mail__c, LastName, Num_ro_piste__c, LeadSource,Phone, Telephone_portable__c, Rating,Type_d_utilisation__c , Origine_connaissance_Kiwatch__c, Client__c, D_sinscription_la_newsletter__c, Inscription_la_newsletter__c, Raison_de_la_d_sinscription__c, Date_de_d_sinscription_la_newsletter__c, Date_d_inscription_la_newsletter__c, Street, City, State, Country, PostalCode  FROM Lead WHERE Adresse_mail__c=\'' + a.Adresse_mail__c + '\'  LIMIT 100';
      

       UpdateFieldAccount batchApex = new UpdateFieldAccount(query, a );
       ID batchprocessid = Database.executeBatch(batchApex);
       
       VerifNoLead batchApex2 = new VerifNoLead(query2, a );
       ID batchprocessid2 = Database.executeBatch(batchApex2);
    
    }
            
}

 

 

Best Answer chosen by Admin (Salesforce Developers) 
Damien_Damien_

I'm not really sure what ur actual question is.... but when I do work on my triggers, I pass the data i need into a static method and do the work there.  I NEVER run a batch from a trigger.

All Answers

Damien_Damien_

I see a few issues with your trigger.  Please read the comments I put into your code.:

 

trigger RechercheDoubleCompte on Account(after insert) {
    for (Account a : Trigger.new) {   
     //You need to bulkify your trigger.  You should not do a query inside of a loop.  Use a Map.
     String query = 'SELECT Salutation, FirstName , Adresse_mail__c, LastName, Numero_client__c, PersonLeadSource, D_sinscription_la_newsletter__c, Inscription_la_newsletter__c, Raison_de_la_d_sinscription__c, Date_de_d_sinscription_la_newsletter__c, Date_d_inscription_la_newsletter__c   FROM Account WHERE Adresse_mail__c=\'' + a.Adresse_mail__c + '\' AND   Id!=\'' + a.Id + '\' LIMIT 100';
     String query2 = 'SELECT  Salutation, FirstName , Adresse_mail__c, LastName, Num_ro_piste__c, LeadSource,Phone, Telephone_portable__c, Rating,Type_d_utilisation__c , Origine_connaissance_Kiwatch__c, Client__c, D_sinscription_la_newsletter__c, Inscription_la_newsletter__c, Raison_de_la_d_sinscription__c, Date_de_d_sinscription_la_newsletter__c, Date_d_inscription_la_newsletter__c, Street, City, State, Country, PostalCode  FROM Lead WHERE Adresse_mail__c=\'' + a.Adresse_mail__c + '\'  LIMIT 100';
      
       //You are trying to make changes to a record that is locked.  Your account can't be modified in an after trigger.  That is what a before trigger is meant for.  If you have a reason where you really MUST do it this way, pass a set of Ids into an @future method in order to accomplish this.  NOTE-I highly recommend NOT doing it this way.  Figure out how you can make changes to your fields in a before trigger instead of after.
       UpdateFieldAccount batchApex = new UpdateFieldAccount(query, a );
       ID batchprocessid = Database.executeBatch(batchApex);
       
       VerifNoLead batchApex2 = new VerifNoLead(query2, a );
       ID batchprocessid2 = Database.executeBatch(batchApex2);
    
    }
            
}

This should help you for best practices.  Pay special attention to #9 for bulkifying your code with maps:

http://wiki.developerforce.com/page/Apex_Code_Best_Practices

alexjalexj

If I understand, Map enable to link the account created to the result of the query.

I have changed my trigger  :

trigger RechercheDoubleCompte on Account(before insert, before update) {
    Set<Id> leadIds = new Set<Id>();
    for(Account a : Trigger.new)
        leadIds.add(a.PersonContactId);
    Map<Id,Lead> leads = new Map<Id, Lead>(
        [select id, LastName, Adresse_mail__c  from Lead where id in :leadIds]);
    for (Account a : Trigger.new){
        if(leads.get(a.PersonContactId).Adresse_mail__c=='a.Adresse_mail__c'){
            VerifNoLead batchApex2 = new VerifNoLead(leads, a );
            ID batchprocessid2 = Database.executeBatch(batchApex2);
        }
    }      
          
}

Now, it is not only the query  which send to my apex class. How I can use the Map in the apex class?

Should I do all the processing (done in class VerifNoLead) in Trigger class?

Damien_Damien_

I'm not really sure what ur actual question is.... but when I do work on my triggers, I pass the data i need into a static method and do the work there.  I NEVER run a batch from a trigger.

This was selected as the best answer
alexjalexj

Ok,

I will try to rewrite my class on trigger and no call a batch