+ Start a Discussion
sfdctrrsfdctrr 

how to update original object in trigger (after insert) ?

Hi Folks,

               How to update original object fields with update DML statement in trigger after insert event. My code:

 

trigger myTrigger on Account (after insert) {

Account myAccount = trigger.new[0];
myAccount.Type = 'Enterprise Customer';
update myAccount;
}

 

Here the update DML statement throws the exception: System.FinalException: Record is read-only:

 

Please let me know and all suggestions are appreciated with any sample code or correction to above code.

 

Thanks.

bob_buzzardbob_buzzard

Firstly, is it possible to use a before insert trigger, or are you relying on data that would be added by the database (e.g. id).

 

If not, you'll need to create a copy of the record.  There's a few ways to do it, one would be to requery the record:

 

Account myAccount=trigger.new[0];
Account updacc=[select id from account where id = :myAccount.id];

updacc.type='Enterprise Customer';
update updacc;

 

ashish raiashish rai

Hello,

       Well you have to use before insert in that case.You are getting that error because you are trying to menupulate two operation on one instance of that objcet which is not possible at all.But by using the below code you will use only one instance of that object so in this case you will be able to do this. So my point is that you can't do different operation on one instance of object at a time till that record is commited. You can do this by creating another instance of that object by making an SOQL query on that object as sujected by BOB.

trigger myTrigger on Account (before insert)

 {

      trigger.new[0].type='Prospect';

}

 

Think this will help you to know what exactly happening in this case.

sfdctrrsfdctrr

Hi Bob

      Thanks for your help.

            Still i got the same error. We can make the following trigger success with event before insert but i want to do it after insert. BCZ in Salesforce doc it is given that we can perform update/delete DML operation on original object after insert event. so here i'm trying to do it with the following example:

 

trigger myTrigger on Account (after insert) {

Account myAccount=trigger.new[0];
Account updacc=[select id from account where id = :myAccount.id];

updacc.type='Enterprise Customer';
update updacc;
}

 

Salesfore URL for Trigger events, please click on the below link and see the event after insert:

http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_triggers_context_variables_considerations.htm

 

Thanks.

 

JohanLiljegrenJohanLiljegren
If this is your exact use case, you should be able to use a 'before' trigger.
Here's an example - please note it's not bulk safe, but rather a simple example.

trigger myTrigger on Account (before insert) {
trigger.new[0].type='Enterprise Customer';
}
r999r999

Hi All,

I am trying to update a field in the same object after inserting, with the new data - But the outstanding__c field is not updating.

Please check my below trigger and give me any solution for this.

Thanks in advance,

 

trigger feedue on Payment__c (after insert) {
for(Payment__c p:Trigger.New)
{
Payment__c c=[select due__c from payment__c where id=:p.id];
Payment__c m=[select outstanding__c from payment__c where id=:p.id];
c.due__c=m.outstanding__c=c.due__c;
update m;
}
}

venk1255venk1255

Hi Sfdctrr  r999

 

see this below code it will fit to your requirement,

 

trigger myTrigger on Account (after insert,after update)
 {
if(updation.isfutureupdate!=true)
{
Set<id> idsToProcess=new Set<id>();

for(account acc:trigger.new)
{
if(acc.Account_Type__c==Null)
{
idsToProcess.add(acc.id);

}
}
helloworld1.proccedaccounts(idsToProcess);
}
}

 

class

____________

 

public class helloworld1
{
//@future
public static void proccedaccounts(set<id> IDs)
{
list<account> lstname=new list<account>();
 for(Account a:[select id,Account_Type__c from account where id IN:IDs])
 {
 a.Account_Type__c='EnterpriseCustomer';
 lstname.add(a);
 }
 
 updation.isfutureupdate=true;
update lstname;
}
}

 

class

________

public class updation
{
public static boolean isfutureupdate=false;
}

 

 

 

if this correct to your requirement accept as solution it will help for some other people

tggagnetggagne
I need to create an MD5 hash of the ID to obscure it from URLs.  Others may be OK with base64 or other ways to change it, but the translation needs to happen /after/ the insert because the ID doesn't exist until after the insert.

I was getting various errors, including read-only complaints, so I thought I'd try one more thing before going the @future route.
 
trigger ContactAfterInsert on Contact (after insert) {
	list<Contact> aList = new list<Contact>();
	
	for (Contact each : trigger.new) {
		Contact aContact = new Contact(id = each.id);
		aContact.idhash__c = Shopper.GenerateMD5Digest(aContact.id);
		aList.add(aContact);
	}
	
	update aList;
}

I only needed to update a single field, so instead of updating the objects already in the trigger I figured using "new Contact(id = each.id);" to create a "new" object separate from the "old" one, then update those.

My unit test ran successfully, which was simply,
        Contact aContact = new Contact(
    		firstName = 'first',
    		lastName = 'contact'
    	);
    	
    	insert aContact;
    	aContact = [ select id, idHash__c from Contact where id = :aContact.id limit 1];
    	system.assertEquals(Shopper.GenerateMD5Digest(aContact.id), aContact.idHash__c);

Now, I just need to figure out how to do the same for PersonAccounts and life will be grand.
PranayMistryPranayMistry
We had a business requirement to capture the user license expiration date for each user record and it was basically 3 years from the created date of the user. Since created date is a system generated field, formula fields, workflow rules were not applicable and trigger was the only way to go. The below trigger worked perfectly fine for me and it is basically after inserting a new user record it will create a userlist in the memory which will contain only 1 user record to avoid the record from becoming read only. Call a new trigger on the user object, update the Expiration date for a temp user object, add the user to the user list and then update the user list object. This way even if you are doing an import of 1000 users from an excel import or data import, you will be good as there is only 1 DML statement executed on 1 user list that contains only 1 user object and in turn 1 user record to be updated. 
 
trigger SetUserExpirationDate on User (after insert) {    
    List<User> ul = new List<User>();
    for (User u : Trigger.new) {    
        User usertoUpdate = new User(Id = u.Id, Expiration_Date__c = u.CreatedDate.addYears(3));
        ul.add(usertoUpdate);            
    }
    update ul;
}

 
RaspikabekRaspikabek
Normally you can update with a DML operation in after insert. Try it with a deepclone: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_sobject.htm#apex_System_SObject_clone
 
trigger myTrigger on Account(after insert){
    List<Account> lAccounts = new List<Account>();
    for(Account a : trigger.new){
        Account temp = a.clone(true,true);
        lAccounts.add(temp);
    }
    update lAccounts;
}

 
Anil Srinivas 5Anil Srinivas 5
Thanks  PranayMistry, your soln helped me too !