10

I have an issue where my my org is uploading a ton of leads at a time via the dataloader. These new leads could potentially be existing accounts / leads and need to be merged to their latest associated record.

The issue I'm having is, imagine a batch of 200 records hits my trigger and all have to be merged with older leads. Only 150 DML statements are allowed, and each merge has to be done one at a time which causes an issue.

I know the Salesforce API has an object called MergeRequest which allows you to do a collection of merges within a single call.

Has anyone been able to figure out an efficient way of achieving this? Also, does anyone know if the API can be called within a trigger / apex?

3

Yes, you can call the SOAP API from Apex, although the process is not well documented. And you can use the API to merge via MergeRequest object; I've just tested it.

First, you'll need to export the Partner WSDL (Setup->Develop->API) and then import it to create Apex classes (Setup->Develop->Apex Classes->Generate From WSDL). The good news is that whereas previously, you couldn't import the WSDL directly (due to naming conflicts), that seems to be fixed; the importer automatically appends _x to problematic names, so (for example) merge becomes merge_x.

When you import the WSDL, you'll have to choose names for the generated Apex classes (one per namespace), for my example code below, I chose class names as follows:

  • urn:sobject.partner.soap.sforce.com -> PartnerSObject
  • urn:fault.partner.soap.sforce.com -> PartnerAPIFaults
  • urn:partner.soap.sforce.com -> PartnerAPI

You will also need to add your salesforce server to the remote site settings to allow soap callouts.

With those preliminaries out of the way, here's some basic code to prove it works. I didn't write it as a test class as I was working with the code iteratively in the Developer Console, and checking the log after each run. To test in your org, make sure you create accounts named "Merge Test A" and "Merge Test B". For extra proof, create a contact on account B, so you can see it reparented to Account A.

public class SoapMergeTest{

    public static void DoMerge() {
        Account AcctA = [select id, name from Account where name = 'Merge Test A'];
        Account AcctB = [select id, name from Account where name = 'Merge Test B'];

        //use current session instead of logging in.  
        //Will need to update enpoint as well (Login method normally handles this)        
        PartnerAPI.Soap soap = new PartnerAPI.Soap();
        //TODO: make this more robust, instead of hardcoding login url
        soap.endpoint_x = soap.endpoint_x.replace('login.salesforce.com', URL.getSalesforceBaseUrl().getHost());
        PartnerAPI.SessionHeader_element sessionHeader = new PartnerAPI.SessionHeader_element();
        sessionHeader.sessionId = UserInfo.getSessionId();
        soap.SessionHeader = sessionHeader;

        PartnerAPI.MergeRequest mrq = new PartnerAPI.MergeRequest();
        PartnerSObject.sObject_x objA = new PartnerSObject.sObject_x();
        objA.id = AcctA.id;
        objA.type_x = 'Account';
        mrq.masterRecord = objA;

        mrq.recordToMergeIds = new list<String>{AcctB.id};

        list<PartnerAPI.MergeResult> results = soap.merge_x(new list<PartnerAPI.MergeRequest>{mrq});
        system.debug('Merge Result: ' + results);

    }

}
2

Not the right solution by any means but have you considered just reducing the size of the batch within the data loader (Settings->Options)?enter image description here

  • Yes I have, but I'm not the one who uploads the records, just the developer. I've talked about this, but people tend to be forgetful. Was looking for an alternative other than just changing the batch size. Thanks for the response though. I'm a bit upset Salesforce has this functionality wtihin their API but not APEX. – Double A Sep 5 '12 at 16:42
1

We are testing this app at work:

http://www.ringlead.com/salesforce-applications/unique-upload/

Early in the process but the initial impression is positive. DupeBlocker markets an app which is similar.

0

Instead of using merge(), I would just perform the transaction with bulkable methods, like update and delete.

Your trigger will collect all the email addresses, names, or whatever you need to match on, and query for the matching records. Then update important fields on the old record and either delete or keep the new Lead record, maybe with a Status = 'Inactive' or something. If it's properly bulkified, it requires only one DML and 2 queries per batch.

  • This is true, though then the code would always require updating for moving all child objects to the winning record. Another issue that can arise is pulling back so many of those children records. IE: Tasks, Events... there could be hundreds for each one. – Double A Sep 5 '12 at 17:08

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.