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
sweetzsweetz 

Error in apex trigger

Hi all,

 When I merge account, I want to get the deleted record id and update a field value for the newly merged record.

 

 

trigger accountMerge on Account (after delete) {
public ID MasterRecordIdfield = null;
Account[] acc= Trigger.old; 
MasterRecordIdfield = acc[0].MasterRecordId;
if(MasterRecordIdfield != null && String.valueOf(MasteRecordIdfield).length() >0)
{
Account[] acct = [select Id, name from account where id =:MasterRecordIdField];
for(Account acct:acc)
{
acct.Field_to_update__c = acct.name;
update acct;
}
}
}

 

 

When I execute this, I m getting the following error, I dont know where I am going wrong. Help Please.

 

Apex trigger then.accountMerge caused an unexpected exception, contact your administrator: then.accountMerge: execution of AfterDelete caused by: System.DmlException: Update failed. First exception on row 0 with id 0019000000K7lxGAAR; first error: SELF_REFERENCE_FROM_TRIGGER, Object 0019000000K7lxGAAR is currently in a merge operation, therefore a trigger can not update it.: []: Trigger.then.accountMerge: line 12, column 1

Best Answer chosen by Admin (Salesforce Developers) 
crop1645crop1645

Sweetz - my apologies - APEX hubris had set in. 

 

Future methods won't accept parameters of Map<ID, List<ID>>, so the rewrite is a bit less elegant as it only allows for current SFDC behavior of up to three merged SObjects

 

The trigger

trigger SomeTrigger on Account (after delete) {
	Map<ID,ID> mergeWinnerToFirstLoserIdMap = new Map<ID,ID> (); 
	Map<ID,ID> mergeWinnerToSecondLoserIdMap = new Map<ID,ID> ();		// two maps as we cant pass to future method Map <ID, List<ID>>

	for (Account loser : Trigger.old) {
		if (loser.masterRecordId == null) continue;  // ignore normal account deletes unrelated to merging   
		if (!mergeWinnerToFirstLoserIdMap.containsKey(loser.masterRecordId))
				mergeWinnerToFirstLoserIdMap.put(loser.masterRecordId,loser.id);
		else
				mergeWinnerToSecondLoserIdMap.put(loser.masterRecordId,loser.id);	
	}
	
	if(mergeWinnerToFirstLoserIdMap.size() > 0)		// we found evidence of some merge
		FutureMergeAuditLog.mergeAccupdate(mergeWinnerToFirstLoserIdMap, mergeWinnerToSecondLoserIdMap);
}

 The future class/method

public without sharing class FutureMergeAuditLog {
	@future
	public static void mergeAccupdate(Map<ID,ID> mergeWinnerToFirstLoserIdMap, Map<ID,ID> mergeWinnerToSecondLoserIdMap) {
		Set<ID> winnerAcctIdSet	= new Set<ID> ();
		winnerAcctIdSet.addAll(mergeWinnerToFirstLoserIdMap.keySet());
		winnerAcctIdSet.addAll(mergeWinnerToSecondLoserIdMap.keySet());
		
		List<Account> winnerList = [select id from Account where id IN: winnerAcctIdSet];
		for (Account winner : winnerList) 	{
			String loser1 = mergeWinnerToFirstLoserIdMap.containsKey(winner.id) 
								? mergeWinnerToFirstLoserIdMap.get(winner.id)
								: null;
			String loser2 = mergeWinnerToSecondLoserIdMap.containsKey(winner.id) 
								? mergeWinnerToSecondLoserIdMap.get(winner.id)
								: null;	
								
			winner.loserid__c = loser1 != null && loser2 != null				// concatenate and comma separate if two
									? loser1 + ',' + loser2
									: (loser1 != null && loser2 == null
										? loser1
										: (loser1 == null && loser2 != null
											? loser2
											: null
											)
										);										
		}
		update winnerList;
	}

}

 

All Answers

Vinita_SFDCVinita_SFDC

Hello,

 

You cannot recursively update or delete the same object from an Apex trigger. This error often occurs when:

        * You try to update or delete an object from within its before trigger.
        * You try to delete an object from within its after trigger.  

 

I would suggest you to use the following App which if free of cost for this requirement:

 

https://appexchange.salesforce.com/listingDetail?listingId=a0N30000003IYLlEAO

sweetzsweetz

Hi Vinita_SFDC,

 

    Thanks for your information. If I want to get a deleted record id and updated record id on merging accounts. What are the things I need to think of? Your help please.  When I merge an account, The master record ID of the deleted account is same as the Merged account. With this comparison, how can I pull both Id and Update the field of a merged account and trigger an outbound message.

crop1645crop1645

Sweetz

 

Your variable naming and for loop seems to be the issue here

 

trigger accountMerge on Account (after delete) {
public ID MasterRecordIdfield = null;
Account[] acc= Trigger.old; // acc = merge loserList
MasterRecordIdfield = acc[0].MasterRecordId;
if(MasterRecordIdfield != null && String.valueOf(MasteRecordIdfield).length() >0)
{
Account[] acct = [select Id, name from account where id =:MasterRecordIdField]; // acct = merge winner
for(Account acct:acc) // you are redefining acct so it is in fact the merge loser (acc is merge loserList so the for loop will assign acct to acc [0], acc[1], ...
{
acct.Field_to_update__c = acct.name; // you are updating the merge loser, not the winner!
update acct;
}
}
}

perhaps the following which is also bulkified:

 

trigger accountMerge on Account (after delete) {

Map<ID,ID> mergeWinnerIdToLoserIdMap = new Map<ID,ID> ();  // maps winner ID to loser Id;
for (Account loser : Trigger.old)
  mergeWinnerIdToLoserIdMap.put(loser.masterRecordId,loser.id);

List<Account> winnerList = [select id from Account where id IN : mergeWinnerIdToLoserIdMap.keySet()];
for (Account winner : winnerList)
   winner.loserName__c = Trigger.oldMap.get(mergeWinnerIdToLoserIdMap.get(winner.id)).name;  // get the loser's account.name from the trigger.oldMap

update winnerList;

}

 

 

 

sweetzsweetz

Thank you so much for your help @crop1645. When I updated the code you have provided I am getting this error

 

Apex trigger then.accountMerge caused an unexpected exception, contact your administrator: then.accountMerge: execution of AfterDelete caused by: System.DmlException: Update failed. First exception on row 0 with id 0019000000K7lxGAAR; first error: SELF_REFERENCE_FROM_TRIGGER, Object 0019000000K7lxGAAR is currently in a merge operation, therefore a trigger can not update it.: []: Trigger.then.accountMerge: line 11, column 1

 

asish1989asish1989

Hi

You can't do update operation in a account on which merging is going on in same time. So you write a another trigger for your task.

Simply use this

trigger updatesomefield on Account (before Update) {
    
    for(Account acc:Trigger.new){
        acc.loserName__c = Trigger.Old[0].Name;
    }

}

 

 

crop1645crop1645

Hmm - 

 

If asish1989's suggestion doesn't work, then use a @future method in a separate class to do the updates of the winner Accounts with the loser's account names.  One thing I also thought of later is that in my bulkified trigger -  'merge' can merge three accounts - two losers and one winner. Thus, the map needs to be Map<ID, List<ID>> winnerIdToLoserIdListMap.

sweetzsweetz

Thanks Ashish and crop for the help. Now i ma ble to update a field only when two records are merged. I want to capture the two record ids that are deleted during merge process when three accounts are merged. As crop said Map list of id's , I m getting error

crop1645crop1645

Sweetz -- we can't help unless you post your current code

sweetzsweetz
trigger accMerge on Account (after delete) {
Map<ID,Id> mergeWinToLoserIdMap = new Map<ID,Id> (); 
List<id> loserId = new List<id>();
set<Id> MasterRecordId = new Set<Id>();
for (Account loser : Trigger.old)
{
mergeWinToLoserIdMap .put(loser.masterRecordId,loser.Id);
}
if(mergeWinToLoserIdMap .size() > 0)
merge.mergeAccupdate(mergeWinToLoserIdMap.keyset(),mergeWinToLoserIdMap);

}

public class merge
{
@future
public static void mergeAccupdate(set<Id> ids, Map<ID,Id> mergeWinToLoserIdMaps)
{
List<Account> winnerList = [select id from Account where id IN: Ids];
for (Account winner : winnerList)
{
winner.loserid__C= mergeWinToLoserIdMaps.get(winner.id);
}

update winnerList;
}

}

 

This works fine for two records in merge process. But when i merge three records I want loserid__C to be updated with two loser id's. That is not working. Help please

 

asish1989asish1989

If you merge three record then two record should be deleted.

for (Account loser : Trigger.old)
{
mergeWinToLoserIdMap .put(loser.masterRecordId,loser.Id);
}

 This for loop will execute two times.

We know that A map is a collection of key-value pairs where each unique key maps to a single value.

 

 mergeWinToLoserIdMap .put(loser.masterRecordId,loser1.Id);

 

 mergeWinToLoserIdMap .put(loser.masterRecordId,loser2.Id);

 

Here value will be different, becasue these are two recordId of looser records,but key is same.

 

That's whay It will override the first value. Finaly the map will contain one id.

 

 

sweetzsweetz

Ya. Thats what, Then In that case how will i update a field with two loser Id?

crop1645crop1645

Sweetz

 

You missed my remark on how the map needs to be different - Map of winnerId to List of loser Ids

 

trigger accMerge on Account (after delete) {
Map<ID,List<Id>> mergeWinnnerToLoserIdListMap = new Map<ID,List<Id>> (); 

for (Account loser : Trigger.old) {
if (loser.masterRecordId == null) continue;  // ignore normal account deletes unrelated to merging   
List<ID> workIdList = mergeWinnnerToLoserIdListMap.containsKey(loser.masterRecordId) ? mergeWinnnerToLoserIdListMap.get(loser.masterRecordId) : new List<ID> ();
   workIdList.add(loser.id);  // append the loser to list of losers for the winner
   mergeWinnnerToLoserIdListMap.put(loser.masterRecordId,workIdList);
}
if(mergeWinnnerToLoserIdListMap.size() > 0)
FutureMergeAuditLog.mergeAccupdate(mergeWinnerToLoserIdListMap);

}

public class FutureMergeAuditLog
{
@future
public static void mergeAccupdate(Map<ID,List<ID>> mergeWinnnerToLoserIdListMap)
{
List<Account> winnerList = [select id from Account where id IN: mergeWinnnerToLoserIdListMap.keySet()];
for (Account winner : winnerList)
{
winner.loserid__C= String.join(mergeWinnerToLoserIdListMap.get(winner.id),',');  // Concatenate all losers into one string, comma separated
}

update winnerList;
}

}

 

sweetzsweetz

I am getting error on trigger "Variable does not exist:mergeWinnnerToLoserIdListMap" on this line FutureMergeAuditLog.mergeAccupdate(mergeWinnerToLoserIdListMap);

 

In class, Error is "Unsupported parameter type Map<Id,List<Id>>" on this line public static void mergeAccupdate(Map<ID,List<ID>> mergeWinnnerToLoserIdListMap)

crop1645crop1645

Sweetz - my apologies - APEX hubris had set in. 

 

Future methods won't accept parameters of Map<ID, List<ID>>, so the rewrite is a bit less elegant as it only allows for current SFDC behavior of up to three merged SObjects

 

The trigger

trigger SomeTrigger on Account (after delete) {
	Map<ID,ID> mergeWinnerToFirstLoserIdMap = new Map<ID,ID> (); 
	Map<ID,ID> mergeWinnerToSecondLoserIdMap = new Map<ID,ID> ();		// two maps as we cant pass to future method Map <ID, List<ID>>

	for (Account loser : Trigger.old) {
		if (loser.masterRecordId == null) continue;  // ignore normal account deletes unrelated to merging   
		if (!mergeWinnerToFirstLoserIdMap.containsKey(loser.masterRecordId))
				mergeWinnerToFirstLoserIdMap.put(loser.masterRecordId,loser.id);
		else
				mergeWinnerToSecondLoserIdMap.put(loser.masterRecordId,loser.id);	
	}
	
	if(mergeWinnerToFirstLoserIdMap.size() > 0)		// we found evidence of some merge
		FutureMergeAuditLog.mergeAccupdate(mergeWinnerToFirstLoserIdMap, mergeWinnerToSecondLoserIdMap);
}

 The future class/method

public without sharing class FutureMergeAuditLog {
	@future
	public static void mergeAccupdate(Map<ID,ID> mergeWinnerToFirstLoserIdMap, Map<ID,ID> mergeWinnerToSecondLoserIdMap) {
		Set<ID> winnerAcctIdSet	= new Set<ID> ();
		winnerAcctIdSet.addAll(mergeWinnerToFirstLoserIdMap.keySet());
		winnerAcctIdSet.addAll(mergeWinnerToSecondLoserIdMap.keySet());
		
		List<Account> winnerList = [select id from Account where id IN: winnerAcctIdSet];
		for (Account winner : winnerList) 	{
			String loser1 = mergeWinnerToFirstLoserIdMap.containsKey(winner.id) 
								? mergeWinnerToFirstLoserIdMap.get(winner.id)
								: null;
			String loser2 = mergeWinnerToSecondLoserIdMap.containsKey(winner.id) 
								? mergeWinnerToSecondLoserIdMap.get(winner.id)
								: null;	
								
			winner.loserid__c = loser1 != null && loser2 != null				// concatenate and comma separate if two
									? loser1 + ',' + loser2
									: (loser1 != null && loser2 == null
										? loser1
										: (loser1 == null && loser2 != null
											? loser2
											: null
											)
										);										
		}
		update winnerList;
	}

}

 

This was selected as the best answer
sweetzsweetz

Thanks crop1645 :-) Its working well now :-)

Ezhil Robert 6Ezhil Robert 6
Hi Sweetz, can you please tell me which one of you code actually working.. because i am also getting the same error as above when i create the triggers and class. 
Ezhil Robert 6Ezhil Robert 6
HI, even I am receiving the same error, can you please tell me what you did to solve both the errors. please help. Thanks.