1

im trying to write tests for this afterUpdate contact trigger:

private void mergeSlaveToMaster(){

    map<Id, Contact> mapOldContact = (Map<Id,Contact>) Trigger.oldMap;

    for(Contact c: (List<Contact>) Trigger.new){
        try
        {
            if(c.Merge_With__c != mapOldContact.get(c.id).Merge_With__c)
            {
                Id masterId = [SELECT Merge_With__r.Id from Contact where id=:c.Merge_With__c][0].Id;
                Contact masterContact = [SELECT ID from Contact where id=:masterId];

                merge masterContact c;
            }
        }
        catch (DmlException e)
        {
            System.debug('An unexpected error has occurred: ' + e.getMessage());
        }
    }

}

that's the test:

@isTest private static void migrateSlaveContactToMaster() {
    Account accountTest = TestUtil.getPartnerAccountByDunsAndName('AccountTest','123456789');
    accountTest.Partner_Type__c = 'Full Partner';
    accountTest.DunsNumber = '123456789';
    insert accountTest;
    String acctId = [SELECT Id from Account][0].Id;

    Contact contactTest = TestUtil.getContactByName('ContactTest1');
    contactTest.AccountId = acctId;
    insert contactTest;
    string firstContactId = [SELECT Id FROM Contact WHERE Name='ContactTest1FirstName ContactTest1LastName'][0].Id;

    Contact contactTest2 = TestUtil.getContactByName('ContactTest2');
    contactTest2.AccountId = acctId;
    insert contactTest2;
    string secondContactId = [SELECT Id FROM Contact WHERE Name='ContactTest2FirstName ContactTest2LastName'][0].Id;

    contactTest2.Merge_With__c = firstContactId;
    update contactTest2;

    integer sum = [SELECT count() FROM Contact WHERE AccountId =:acctId];

    System.assertEquals(1,sum);
}

when i run it, i receive this error in the debug log:

An unexpected error has occurred: Merge failed. First exception on row 0 with id 0036E00000AH2DjQAL; first error: ENTITY_IS_DELETED, entity is deleted: []

im not sure why this error occures, what am i doing wrong? please help

  • Quick thought: Your trigger is bound to fail at some point since you've written SOQL inside a for loop and that too; two SOQL's – Rohit Mourya May 10 '17 at 9:33
  • Query, DML inside a for loop, exception is not handled in catch. You query and expect some data and assign it to an object without checking the if the list returns record. You really need to sit back and rewrite the trigger before writing test class. – Raul May 10 '17 at 9:36
  • the list will always return a record. but i will add it like you said. can you help with the error, though? – Dana Griff May 10 '17 at 9:56
  • Note that Merge DML fires delete and update event triggers. Make sure the execution is controlled. You must check that Merge_With__c is not empty before proceed. – Ashwani May 10 '17 at 10:51
  • @Ashwani i check it in: if(c.Merge_With__c != mapOldContact.get(c.id).Merge_With__c) – Dana Griff May 10 '17 at 11:34
2

The error message is pretty clear about the entity being merged is already deleted when it comes to that. I honestly couldn't identify exactly the flow or conditions that causes it in your code. In fact, there are a lot of improvements you could use in your coding and tests which would help preventing future errors and maybe help understanding this one.

1. Don't do SOQL queries inside loops.

You could create a map from ID to Contact for all Contacts referenced as Merge_With__c, something like this:

Set<Id> merge_contacts_ids = new Set<Id>();
for (Contact c : Trigger.new) {
    if (c.Merge_With__c != null) {
        merge_contacts_ids.add(c.Merge_With__c);
    }
}
Map<Id, Contact> merge_contacts = new Map<Id,Contact>([SELECT Id FROM Contact WHERE IsDeleted = False AND Id IN :merge_contacts_ids]);

Then you can use this in your loop:

for(Contact c: Trigger.new){
    // Check if it changed
    if(c.Merge_With__c != mapOldContact.get(c.id).Merge_With__c) {
        Id masterId = c.Merge_With__c;
        if (masterId != null) {
            if (merge_contacts.containsKey(masterId)) {
                Contact masterContact = merge_contacts.get(masterId);
                merge masterContact c;
            }
        }
    }
}

2. You don't need to query a recently inserted record to get its Id.

Your testing could be improved to something like this:

Contact contactTest = TestUtil.getContactByName('ContactTest1');
contactTest.AccountId = acctId;
insert contactTest;
string firstContactId = contactTest.Id;

Back to your error, are you sure this mergeSlaveToMaster() function is being called in an after update trigger? If this is being called twice for some reason it could be the reason for the Contact already being deleted when it tries to merge them. Another possibility for this error is to have other triggers doing other operations to your data before this one runs.

Checking if the sObject exists before doing a DML operation is a good practice, it will avoid having this kind of exception but still you will need to work on your logic if the desired behavior is not being achieved. But I think it is clearer to have your asserts fail instead of that exception to help you build the trigger logic. Despite not solving your current issue, I hope all this tips help you.

  • i did exactly what you wrote, and changed the test class as well. thank you for that. the thing is i still receive the error. the slave contact is actually deleted and there is no problem with that, the contacts are merged. but why i receive this error, i have no idea... any ideas? – Dana Griff May 11 '17 at 13:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.