• Alex Meza
  • NEWBIE
  • 80 Points
  • Member since 2017

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 1
    Likes Given
  • 12
    Questions
  • 8
    Replies
Is it possible to write a batch apex class that query's more than 750,000 records and performs more than 50,000 record updates?

If so how is this possible?
How can I update more than 10,000 records using an apex batch class at a time?
 

I need help writting a batch class that queries more than 50,000 records and updates more than 10,000 records. I already was able to solve the query issue by writting the batch class below but now I need to update it so that it can update more than 10,000 records at a time. 

Just to give you a basic rundown: I am trying to connect to records across two objects, 1. Contacts and 2. Voter_File_TX__c, via a lookup field that exists Voter_File_TX__c custom object of Voter_File_TX__c.Contact__c.
 
Records across these two objects should be connected on a one to one basis if they have matching First Name, Last Name, and Zipcodes.
 
For the Apex class code of UpdateVoterFileonContacts I am able to have this complete perfectly in My Sandbox where I do not have as many records as my production.
 
However once I upload this code into my production I run into an issue because the Contact object has around 700,000 records while the Voter File Object has around 15 Million records, thus I run into Salesforce Govern Apex Limits. I was able to use the batch class to go over the 50,000 query limit and have it expanded to 50,000,000 Limit.
 
But now I am running into a DML govern limit where I can only update 10,000 Records at a time, when I should be updating around 250,000 records.
 
Because of my business logic I cannot further limit and make the query any more selective than I already have, I need to know if there is a way around this, just like there was a way around the query limit of 50,000 records.
 
Please let me know I have also included the class I am working with below.
 

global class UpdateVoterFileonContacts implements Database.Batchable<sObject>{
    global Database.QueryLocator start(Database.BatchableContext BC){
        String query = ' Select ID,First_Name__c, Last_Name__c,Zipcode__c from Voter_File_TX__c';
        return Database.getQueryLocator(query);
    }
   
    global void execute(Database.BatchableContext info, List<Voter_File_TX__c> scope){
        Set<String> set_Str = new Set<string>();
        Map<String,Contact> mp_Cont;
 
        for(Contact Cont : [Select ID,FirstName,LastName,MailingPostalCode, Voter_File_ID__c From Contact where Contact.voter_File_ID__c != null AND Contact.RNC_ID__c != null LIMIT 50000] ){
            if(mp_Cont==null){
                mp_Cont = new Map<String,Contact>();
            }
            mp_Cont.put(Cont.FirstName +''+ Cont.LastName +''+Cont.MailingPostalCode,Cont);
        }
        for(Voter_File_TX__c VoterList : scope){
            if(mp_Cont!=null && mp_Cont.containsKey(VoterList.First_Name__c +''+ VoterList.Last_Name__c+''+ VoterList.Zipcode__c))
           
            {
                mp_Cont.get(VoterList.First_Name__c +''+ VoterList.Last_Name__c +''+ VoterList.Zipcode__c).Voter_File_ID__c = VoterList.id;
            }
        }
        /* if(mp_Cont!=null && mp_Cont.values()!=null){
            update mp_Cont.values();
        }
        */
       
        if(!mp_Cont.isEmpty()){
            update mp_Cont.values();
        }
    }
   
    global void finish(Database.BatchableContext info){
       
    }
}



The way I am running this class is executing in the developers console and running it anonymously. The end result if this code does work then the Voter_File__TX__c.Contact__C field ought to be populated with the corresponding contact match. 
 
As I said this works in my sandbox but fails in production because of the massive size of my records.
 
Let me know if you have any questions or need anything else.
 
I have a database with an object Voter_File_TX with over 15 million records and have over 700,000 contacts. I need to connect records that have the same First Name, Last Name, and Zipcode across these two via a look up field. 

I had to write a batch apex class that I execute anonymously beacuse of the enormous size of my database. I was told that the only way to do this is to do a batch class that will allow me to query more than 50,000 records at a time in order to match them up against each other. I was able to do this and have them connected in my sandbox where I do not have 15 million records.

However when I ran this into my production enviroment it failed because of SF limit of of 10,000 DML, or ability to change records, at a time. I was then also told that I need to write a batch class within this batch class in order to get over this limit as well. 

Can you please help me out with this I am stuck with this part. 

Below is the Apex Batch Class code. 
 
global class UpdateVoterFileonContacts implements Database.Batchable<sObject>{
    global Database.QueryLocator start(Database.BatchableContext BC){
        String query = ' Select ID,First_Name__c, Last_Name__c,Zipcode__c from Voter_File_TX__c';
        return Database.getQueryLocator(query);
    }
    
    global void execute(Database.BatchableContext info, List<Voter_File_TX__c> scope){
        Set<String> set_Str = new Set<string>();
        Map<String,Contact> mp_Cont;

        for(Contact Cont : [Select ID,FirstName,LastName,MailingPostalCode, Voter_File_ID__c From Contact where Contact.voter_File_ID__c = null AND Contact.RNC_ID__c != null LIMIT 50000] ){
            if(mp_Cont==null){
                mp_Cont = new Map<String,Contact>();
            }
            mp_Cont.put(Cont.FirstName +''+ Cont.LastName +''+Cont.MailingPostalCode,Cont);
        }
        for(Voter_File_TX__c VoterList : scope){
            if(mp_Cont!=null && mp_Cont.containsKey(VoterList.First_Name__c +''+ VoterList.Last_Name__c+''+ VoterList.Zipcode__c))
            
            {
                mp_Cont.get(VoterList.First_Name__c +''+ VoterList.Last_Name__c +''+ VoterList.Zipcode__c).Voter_File_ID__c = VoterList.id;
            }
        }
        /* if(mp_Cont!=null && mp_Cont.values()!=null){
            update mp_Cont.values();
        }
        */
        
        if(!mp_Cont.isEmpty()){
            update mp_Cont.values();
        }
    }
    
    global void finish(Database.BatchableContext info){
        
    }
}


I was told that I need to add this type of call to my apex code but I am not sure where how this would transalte into my apex batch class code because I am already currently writting an apex batch class and because i do not know where exactly to add it. 

 

Example Code to add: 

List abc = [Select Id from Contact where Amount =100]; 
for(i=0; i<=abc.size(); i++) 
{ 
List a = abc[i]; 
a.add(abc); 
}

Can anyone please help implment this or tell me of another way wherre I can get around Salesforce govern limit of only updating 10,000 records at a time?

Thanks!
I am trying to deploy one of my batch classes into my production enviroment but I currnelty was only able to write a batch test class that has 29 percent coverage. I was wondering if you guys could help me get my coverage up to 100% so that I can deploy to production. 

Apex Batch Class
global class UpdateContactsVoter implements Database.Batchable<sObject>{
    global Database.QueryLocator start(Database.BatchableContext BC){
        String query = 'Select ID,FirstName,LastName,MailingPostalCode from contact where contact.voter_file_id__c = null';
        return Database.getQueryLocator(query);
    }
    
    global void execute(Database.BatchableContext info, List<contact> scope){
        Set<String> set_Str = new Set<string>();
                                Map<String,Voter_File_TX__c> mp_VoterFile;

        for(Voter_File_TX__c VoterFile : [Select ID,First_Name__c, Last_Name__c,Zipcode__c, Contact__c From Voter_File_TX__c] ){
                                                if(mp_VoterFile==null){
                                                                mp_VoterFile = new Map<String,Voter_File_TX__c>();
                                                }
                                                mp_VoterFile.put(VoterFile.First_Name__c +''+VoterFile.Last_Name__c +''+VoterFile.Zipcode__c,VoterFile);
                                }
                                for(Contact ContactList : scope){
                                                if(mp_VoterFile!=null && mp_VoterFile.containsKey(ContactList.FirstName+''+ ContactList.LastName+''+ ContactList.MailingPostalCode))
            
            {
                                                                mp_VoterFile.get(ContactList.FirstName +''+ ContactList.LastName +''+ ContactList.MailingPostalCode).Contact__c = ContactList.id;
                                                }
                                }
                                if(mp_VoterFile!=null && mp_VoterFile.values()!=null){
                                                update mp_VoterFile.values();
                                }
    }
    
    global void finish(Database.BatchableContext info){
        
    }
}

Test Class
@isTest
public class TestClassUpdateContacts
{
static testMethod void testMethod1()
{
List lstContact= new List();
List lstVoterfile = new List();
if(contact.voter_file_id__c == null && voter_file_tx__c.contact__c == null)
{
Contact cont = new Contact();
cont.FirstName ='Test';
cont.LastName = 'Test';
cont.id = 'Test';
cont.MailingPostalCode = 'test';

insert cont;

Voter_File_TX__c vf = new Voter_File_TX__c();
vf.First_Name__c ='Test';
vf.Last_Name__c ='Test';
vf.RNC_ID__c = 'Test';
vf.Zipcode__c = 'Test';
vf.First_Name__c = cont.FirstName ;
vf.Last_Name__c = cont.LastName ;
vf.Zipcode__c = cont.MailingPostalCode ;
vf.Contact__c = cont.Id ;

insert vf;

cont.FirstName = vf.First_Name__c ;
cont.LastName = vf.Last_Name__c ;
cont.MailingPostalCode = vf.Zipcode__c;
cont.RNC_ID__c = vf.RNC_ID__c ;

update cont;
}
else {
contact cont1 = new Contact();
Voter_File_TX__c vf1 = new Voter_File_TX__c();
cont1.Voter_File_ID__c = null;
vf1.Contact__c = null;

}
insert lstContact;
update lstContact;

Test.startTest();

UpdateContactsVoter obj = new UpdateContactsVoter();
DataBase.executeBatch(obj);

Test.stopTest();
}
}

 
I have an apex batch class that I was able to get workig in my sandbox enviorment and that is ready for deployment into my production enviroment. 

However when I went to write the test class for this I ran into some trouble, with an error message that says line 50 = Test Class Error: Argument must be an object that implements Database.Batchable.

Can you guys help me get over this hurdle or tell me if i need a new test class code in order to be able to deploy to production? Below are my batch class and my test class thanks. 

Batch Class
global class UpdateContactsVoter implements Database.Batchable<sObject>{
    global Database.QueryLocator start(Database.BatchableContext BC){
        String query = 'Select ID,FirstName,LastName,MailingPostalCode from contact where contact.voter_file_id__c = null';
        return Database.getQueryLocator(query);
    }
    
    global void execute(Database.BatchableContext info, List<contact> scope){
        Set<String> set_Str = new Set<string>();
                                Map<String,Voter_File_TX__c> mp_VoterFile;

        for(Voter_File_TX__c VoterFile : [Select ID,First_Name__c, Last_Name__c,Zipcode__c, Contact__c From Voter_File_TX__c] ){
                                                if(mp_VoterFile==null){
                                                                mp_VoterFile = new Map<String,Voter_File_TX__c>();
                                                }
                                                mp_VoterFile.put(VoterFile.First_Name__c +''+VoterFile.Last_Name__c +''+VoterFile.Zipcode__c,VoterFile);
                                }
                                for(Contact ContactList : scope){
                                                if(mp_VoterFile!=null && mp_VoterFile.containsKey(ContactList.FirstName+''+ ContactList.LastName+''+ ContactList.MailingPostalCode))
            
            {
                                                                mp_VoterFile.get(ContactList.FirstName +''+ ContactList.LastName +''+ ContactList.MailingPostalCode).Contact__c = ContactList.id;
                                                }
                                }
                                if(mp_VoterFile!=null && mp_VoterFile.values()!=null){
                                                update mp_VoterFile.values();
                                }
    }
    
    global void finish(Database.BatchableContext info){
        
    }
}


Test Class
 line 50 = Test Class Error: Argument must be an object that implements Database.Batchable.

@isTest 
public class TestClassUpdateContacts 
{
    static testMethod void testMethod1() 
    {
        List<Contact> lstContact= new List<Contact>();
        List<Voter_File_TX__c> lstVoterfile = new List<Voter_File_TX__c>();
        if(contact.voter_file_id__c == null && voter_file_tx__c.contact__c == null)
        {
        Contact cont = new Contact();
        cont.FirstName ='Test';
        cont.LastName = 'Test';
        cont.id = 'Test';
        cont.MailingPostalCode = 'test';
            
        insert cont;
            
        Voter_File_TX__c vf = new Voter_File_TX__c();
        vf.First_Name__c ='Test';
        vf.Last_Name__c ='Test';
        vf.RNC_ID__c = 'Test';
        vf.Zipcode__c = 'Test'; 
                                vf.First_Name__c = cont.FirstName ;
        vf.Last_Name__c = cont.LastName ;
        vf.Zipcode__c = cont.MailingPostalCode ;
        vf.Contact__c = cont.Id ;
        
        insert vf;
       
        cont.FirstName = vf.First_Name__c ;
        cont.LastName = vf.Last_Name__c ;
        cont.MailingPostalCode = vf.Zipcode__c;
        cont.RNC_ID__c = vf.RNC_ID__c ;
            
                                update cont;
        }
        else {
         contact cont1 = new Contact(); 
         Voter_File_TX__c vf1 = new Voter_File_TX__c();
         cont1.Voter_File_ID__c = null;
         vf1.Contact__c = null; 
          
        }
        insert lstContact;
        update lstContact;
        
        Test.startTest();

            TestClassUpdateContacts obj = new TestClassUpdateContacts();
            DataBase.executeBatch(obj); 
            
        Test.stopTest();
    }
}
 


 

I wrote an apex trigger that connected two of my objects (Contacts and Voter File-custom object) via a look up field if they had the same first name, last name, and zipcode. 

I was able to succesfully to this however, once I deployed to production I found out that my query was to large as I was trying to match across 15 million records or so. 

After looking into I found out that I had to write an apex Batch class in order to have this work succesfully with my 15 million plus records, however now I am stuck.

I tried looking up some articles but I am not really sure what way to go such as if I have to start all over or just write the batch class based off the trigger I already wrote. 

The trigger is below if you guys could help me with this I would be able to write the classes for my other triggers. 

Thanks. 
 
trigger Contact2VoterID on Contact (before insert,before update,after insert,after update) 
{
{
    Set<String> set_Str = new Set<string>();
    Map<String,Voter_File_TX__c> mp_VoterFile;
    
    if(Trigger.isAfter && Trigger.isUpdate)
    {
        for(Voter_File_TX__c VoterFile : [Select ID,First_Name__c, Last_Name__c,Zipcode__c, Contact__c From Voter_File_TX__c])
        {
                    if(mp_VoterFile==null)
                        mp_VoterFile = new Map<String,Voter_File_TX__c>();
            
            mp_VoterFile.put(VoterFile.First_Name__c +''+VoterFile.Last_Name__c +''+VoterFile.Zipcode__c,VoterFile);

 
                    }
        
        for(Contact ContactList : Trigger.new)
    {
        if(mp_VoterFile!=null && mp_VoterFile.containsKey(ContactList.FirstName+''+ ContactList.LastName+''+ ContactList.MailingPostalCode))

        {

       mp_VoterFile.get(ContactList.FirstName +''+ ContactList.LastName +''+ ContactList.MailingPostalCode).Contact__c = ContactList.id;

}

}
 
if(mp_VoterFile!=null && mp_VoterFile.values()!=null)
        update mp_VoterFile.values();

    }
}
}



 

I was able to write two apex triggers that connect two objects(Contacts and a Custom Object) via a lookup field when they have the same first name, last name, and zip code. This was done in my sandbox environment and I was able to get this working perfectly there. I then, with help through the moudles and references, was able to write a small sample test class in order to have this deployed in my production environment, but i am only able to get 24 percent coverage. 

Please help as I am stuck, below is one of my triggers and my test class. 

 

trigger VoterID2Contact on Voter_File_TX__c (before insert,before update,after insert,after update) 

{ if(checkRecursive.runOnce){ return;}
{
    Set<String> set_Str = new Set<string>();
    Map<String,Contact> mp_ContactID;
    
    if(Trigger.isAfter && Trigger.isUpdate)
    {
        for(Contact ContactID : [Select ID,FirstName, LastName,MailingPostalCode, Voter_File_ID__c From Contact])
        {
                    if(mp_ContactID==null)
                        mp_ContactID = new Map<String,Contact>();
            
            mp_ContactID.put(ContactID.FirstName +''+ContactID.LastName +''+ContactID.MailingPostalCode,ContactID);

 
                    }
        
        for(Voter_File_TX__c VoterList : Trigger.new)
    {
        if(mp_ContactID!=null && mp_ContactID.containsKey(VoterList.First_Name__c+''+ VoterList.Last_Name__c+''+ VoterList.Zipcode__c))

        {

       mp_ContactID.get(VoterList.First_Name__c +''+ VoterList.Last_Name__c +''+ VoterList.Zipcode__c).Voter_File_ID__c = VoterList.id;

}

}
 
if(mp_ContactID!=null && mp_ContactID.values()!=null)
        checkRecursive.runOnce = true;
        update mp_ContactID.values();

    }
}
}

and this is my test class
 
@isTest
public class TestClass 
{
    static testMethod void testMethod1()
    {
        
        Voter_File_TX__c vf = new Voter_File_TX__c();
        vf.First_Name__c ='Test';
        vf.Last_Name__c ='Test';
        vf.RNC_ID__c = 'Test';
        vf.Zipcode__c = 'Test'; 
        
         insert vf;

        Contact cont = new Contact();
        cont.FirstName ='Test';
        cont.LastName = 'Test';
        cont.RNC_ID__c = 'Test';
        cont.MailingPostalCode = 'test';
    
        insert cont;
        
        vf.First_Name__c = cont.FirstName ;
        vf.Last_Name__c = cont.LastName ;
        vf.Zipcode__c = cont.MailingPostalCode ;
        vf.RNC_ID__c = cont.RNC_ID__c ;
        vf.Contact__c = cont.Id ;
        
        cont.FirstName = vf.First_Name__c ;
        cont.LastName = vf.Last_Name__c ;
        cont.MailingPostalCode = vf.Zipcode__c;
        cont.RNC_ID__c = vf.RNC_ID__c ;
        
       
    }

}

 
I was able to fully write 2 apex triggers and 1 apex class in my Sandbox, however I am having trouble writting the apex test class that is required for deployment into my production enviroment. I was wondering if you guys could help me with writting a coresponding trigger code for one of them, that way I can just go off of that and write the test classes for the other triggers. Thanks.


trigger Contact2VoterID on Contact (before insert,before update,after insert,after update) 
{
{
    Set<String> set_Str = new Set<string>();
    Map<String,Voter_File_TX__c> mp_VoterFile;
    
    if(Trigger.isAfter && Trigger.isUpdate)
    {
        for(Voter_File_TX__c VoterFile : [Select ID,First_Name__c, Last_Name__c,Zipcode__c, Contact__c From Voter_File_TX__c])
        {
                    if(mp_VoterFile==null)
                        mp_VoterFile = new Map<String,Voter_File_TX__c>();
            
            mp_VoterFile.put(VoterFile.First_Name__c +''+VoterFile.Last_Name__c +''+VoterFile.Zipcode__c,VoterFile);

 
                    }
        
        for(Contact ContactList : Trigger.new)
    {
        if(mp_VoterFile!=null && mp_VoterFile.containsKey(ContactList.FirstName+''+ ContactList.LastName+''+ ContactList.MailingPostalCode))

        {

       mp_VoterFile.get(ContactList.FirstName +''+ ContactList.LastName +''+ ContactList.MailingPostalCode).Contact__c = ContactList.id;

}

}
 
if(mp_VoterFile!=null && mp_VoterFile.values()!=null)
        update mp_VoterFile.values();

    }
}
}

 
I was able to write 2 triggers for two different custom objects TGA_Email_List__c and Voter_File__c. Both triggers look for a match between the two custom objects, of first name, last name, and zipcode and if a match found then one trigger auto populates the lookup field of Voter_ID_del__c on TGA_Email_List custom object, while the other trigger auto populates the look up field of Email_ID_del__c on the Voter_File__c object. 

These triggers work great if I run them indvidually, having only one of them active. However, when I have both of the triggers active they run into a recusrvie error because both are set to run when a reocrd in that object is update or created, thus creating a constant error and rescursive loop that goes on forever. Both Triggers are below.

Trigger 1:
trigger EmailtoVoterFile on TGA_Email_List__c (before insert,before update,after insert,after update)
{ if(checkRecursive.runOnce())
{
    Set<String> set_Str = new Set<string>();
    Map<String,Voter_File__c> mp_voterfileObj;
    
    if(Trigger.isAfter && Trigger.isUpdate)
    {
        for(Voter_File__c voterfileobj : [Select ID,First_Name__c, Last_Name__c,ZipCode__c, Email_ID_del__c From Voter_File__c])
        {
                    if(mp_VoterfileObj==null)
                        mp_VoterFileObj = new Map<String,Voter_File__c>();
            
            mp_VoterFileobj.put(voterfileobj.First_Name__c +''+voterfileobj.Last_Name__c +''+voterfileobj.Zipcode__c,voterfileobj);

 
                    }
        
        for(TGA_Email_List__c TGAEmailListobj : Trigger.new)
    {
        if(mp_VoterFileObj!=null && mp_Voterfileobj.containsKey(TGAEmailListobj.First_Name__c +''+ TGAEmailListobj.Last_Name__c +''+ TGAEmailLIstobj.Zipcode__c))

        {

       mp_Voterfileobj.get(TGAEmailListobj.First_Name__c +''+ TGAEmailLIstobj.Last_Name__c +''+ TGAEmailListobj.Zipcode__c).Email_ID_del__c = TGAEmailListobj.id;

}

}
 
if(mp_VoterFileObj!=null && mp_VoterFileObj.values()!=null)
        update mp_VoterFileObj.values();

    }
}
}

Trigger 2:
trigger VoterIDUpdate on Voter_File__c (before insert,before update,after insert,after update) 
{ if(checkRecursive.runOnce())
{
    Set<String> set_Str = new Set<string>();
    Map<String,TGA_Email_List__c> mp_EmailList;
    
    if(Trigger.isAfter && Trigger.isUpdate)
    {
        for(TGA_Email_List__c EmailList : [Select ID,First_Name__c, Last_Name__c,ZipCode__c, Voter_ID_del__c From TGA_Email_List__c])
        {
                    if(mp_EmailList==null)
                        mp_EmailList = new Map<String,TGA_Email_List__c>();
            
            mp_EmailList.put(EmailList.First_Name__c +''+EmailList.Last_Name__c +''+EmailList.Zipcode__c,EmailList);

 
                    }
        
        for(Voter_File__c VoterID : Trigger.new)
    {
        if(mp_EmailList!=null && mp_EmailList.containsKey(VoterID.First_Name__c +''+ VoterID.Last_Name__c +''+ VoterID.Zipcode__c))

        {

       mp_EmailList.get(VoterID.First_Name__c +''+ VoterID.Last_Name__c +''+ VoterID.Zipcode__c).Voter_ID_del__c = VoterID.id;

}

}
 
if(mp_EmailList!=null && mp_EmailList.values()!=null)
        update mp_EmailList.values();

    }
}
}

I then wrote a class and included a code in the triggers that would solve this issue and have it only run once if it was recusrive, however when I did this then and activated both triggers none of the fields were being auto populated if a match was found, also there was no error being thrown out. 

Class:
public class checkRecursive {
    private static boolean run = true;
    public static boolean runOnce(){
    if(run){
     run=false;
     return true;
    }else{
        return run;
    }
    }  
}

My question is how do I get this to work so that I can have both of lookup fields auto populate based on a match on both custom objects, while also not getting a recuring error. 

Please, help I am stuck, Thanks!
 
I am trying to set up a connection where I can connect two custom objects that have the same custom field values such as first, last name, and/or zipcode, via a look up field that connects them by their salesforce generated record ID. If matching records based off of these custom feilds are found then the connection needs to autopopulate this lookup field that points back to each objecet, which in this case is just the standard Salesforce generated ID of each record in their respective custom object.

I was able to get started with some help and have come up with the apex trigger code below, that i wrote to match just based off of one custom field match in First Name, once I get the basic structure down then I will expand to include other custom fields too match. 

However, I am running into an error on line 13 where it says Incompatible key type Schema.SObjectField for Map<String,Voter_File__c>.  Also for the purpose of just figuring out this inital code and logic i've simplfied it to only look for matches base off first name.

With this my first custom objects= TGA Email List, and my second is= Voter File

Where the lookup field I am trying to update is Voter_ID_del__c on the TGA Email List custom object, where Voter_ID_del__c is the salesforce generated id record for a record in the Voter File custom object. 

Also note because realtionships between these two custom objects should be one to one, there is a lookup field on the Voter File object that reads Email_ID_del__c which is simply the Unique salesforce generated id record of the TGA Emai List Record. 

Am I on the right track so far also is there anything wrong I am doing. Thanks. 
 
trigger EmailtoVoterFile on TGA_Email_List__c (before insert,before update,after insert,after update)
{
	Set<String> set_Str = new Set<string>();
    Map<String,Voter_File__c> mp_voterfileObj;
    
    if(Trigger.isAfter && Trigger.isUpdate)
    {
        for(Voter_File__c voterfileobj : [Select ID,First_Name__c,Email_ID_del__c From Voter_File__c])
        {
            		if(mp_VoterfileObj==null)
                        mp_VoterFileObj = new map<String,Voter_File__c>();
        
            mp_VoterFileObj.put(Voter_File__c.First_Name__c,VoterFileObj);

 
                    }
        
        for(TGA_Email_List__c TGAEmailListobj : Trigger.new)
    {
        if(mp_VoterFileObj!=null && mp_Voter_File__c.containsKey(TGA_Email_List__c.First_Name__c))

        {

       mp_Voter_File__c.get(TGA_Email_List__c.First_Name__c).Voter_ID_del__c = Voter_File__c.id;

}

}
 
if(mp_VoterFileObj!=null && mp_Voter_File__c.values()!=null)
		update mp_Voter_File__c.values();

    }
}


 
Hello, I am trying to set up a connection where I can connect two custom objects that have the same custom field values such as first, last name, and/or zipcode. If matching records based off of these custom feilds are found then the connection needs to autopopulate the lookup field that points back to each objecet, which in this case is just the standard Salesforce generated ID of each record in their respective custom object.

Technically, what I want to happen is for there to be a scan of all records in one object and look for any matches based off one or multiple custom fields in another object, after that have an automation that will happen to connect those matching records.

I tired doing this through the process builder, and the workflow but I had no luck, I was then told by techical support that Apex Trigger would be the only way to do this. 

Please help, also If I am unclear please let me know. 

Thanks. 
I have to pull up lead or contact info in HTML email template.
Can someone explain me what's this mean %%first_name%% , %%view_online%%
%%Oraganization%%

I need to replace value in Salesforce with above info.
How can I update more than 10,000 records using an apex batch class at a time?
 
I have an apex batch class that I was able to get workig in my sandbox enviorment and that is ready for deployment into my production enviroment. 

However when I went to write the test class for this I ran into some trouble, with an error message that says line 50 = Test Class Error: Argument must be an object that implements Database.Batchable.

Can you guys help me get over this hurdle or tell me if i need a new test class code in order to be able to deploy to production? Below are my batch class and my test class thanks. 

Batch Class
global class UpdateContactsVoter implements Database.Batchable<sObject>{
    global Database.QueryLocator start(Database.BatchableContext BC){
        String query = 'Select ID,FirstName,LastName,MailingPostalCode from contact where contact.voter_file_id__c = null';
        return Database.getQueryLocator(query);
    }
    
    global void execute(Database.BatchableContext info, List<contact> scope){
        Set<String> set_Str = new Set<string>();
                                Map<String,Voter_File_TX__c> mp_VoterFile;

        for(Voter_File_TX__c VoterFile : [Select ID,First_Name__c, Last_Name__c,Zipcode__c, Contact__c From Voter_File_TX__c] ){
                                                if(mp_VoterFile==null){
                                                                mp_VoterFile = new Map<String,Voter_File_TX__c>();
                                                }
                                                mp_VoterFile.put(VoterFile.First_Name__c +''+VoterFile.Last_Name__c +''+VoterFile.Zipcode__c,VoterFile);
                                }
                                for(Contact ContactList : scope){
                                                if(mp_VoterFile!=null && mp_VoterFile.containsKey(ContactList.FirstName+''+ ContactList.LastName+''+ ContactList.MailingPostalCode))
            
            {
                                                                mp_VoterFile.get(ContactList.FirstName +''+ ContactList.LastName +''+ ContactList.MailingPostalCode).Contact__c = ContactList.id;
                                                }
                                }
                                if(mp_VoterFile!=null && mp_VoterFile.values()!=null){
                                                update mp_VoterFile.values();
                                }
    }
    
    global void finish(Database.BatchableContext info){
        
    }
}


Test Class
 line 50 = Test Class Error: Argument must be an object that implements Database.Batchable.

@isTest 
public class TestClassUpdateContacts 
{
    static testMethod void testMethod1() 
    {
        List<Contact> lstContact= new List<Contact>();
        List<Voter_File_TX__c> lstVoterfile = new List<Voter_File_TX__c>();
        if(contact.voter_file_id__c == null && voter_file_tx__c.contact__c == null)
        {
        Contact cont = new Contact();
        cont.FirstName ='Test';
        cont.LastName = 'Test';
        cont.id = 'Test';
        cont.MailingPostalCode = 'test';
            
        insert cont;
            
        Voter_File_TX__c vf = new Voter_File_TX__c();
        vf.First_Name__c ='Test';
        vf.Last_Name__c ='Test';
        vf.RNC_ID__c = 'Test';
        vf.Zipcode__c = 'Test'; 
                                vf.First_Name__c = cont.FirstName ;
        vf.Last_Name__c = cont.LastName ;
        vf.Zipcode__c = cont.MailingPostalCode ;
        vf.Contact__c = cont.Id ;
        
        insert vf;
       
        cont.FirstName = vf.First_Name__c ;
        cont.LastName = vf.Last_Name__c ;
        cont.MailingPostalCode = vf.Zipcode__c;
        cont.RNC_ID__c = vf.RNC_ID__c ;
            
                                update cont;
        }
        else {
         contact cont1 = new Contact(); 
         Voter_File_TX__c vf1 = new Voter_File_TX__c();
         cont1.Voter_File_ID__c = null;
         vf1.Contact__c = null; 
          
        }
        insert lstContact;
        update lstContact;
        
        Test.startTest();

            TestClassUpdateContacts obj = new TestClassUpdateContacts();
            DataBase.executeBatch(obj); 
            
        Test.stopTest();
    }
}
 


 

I wrote an apex trigger that connected two of my objects (Contacts and Voter File-custom object) via a look up field if they had the same first name, last name, and zipcode. 

I was able to succesfully to this however, once I deployed to production I found out that my query was to large as I was trying to match across 15 million records or so. 

After looking into I found out that I had to write an apex Batch class in order to have this work succesfully with my 15 million plus records, however now I am stuck.

I tried looking up some articles but I am not really sure what way to go such as if I have to start all over or just write the batch class based off the trigger I already wrote. 

The trigger is below if you guys could help me with this I would be able to write the classes for my other triggers. 

Thanks. 
 
trigger Contact2VoterID on Contact (before insert,before update,after insert,after update) 
{
{
    Set<String> set_Str = new Set<string>();
    Map<String,Voter_File_TX__c> mp_VoterFile;
    
    if(Trigger.isAfter && Trigger.isUpdate)
    {
        for(Voter_File_TX__c VoterFile : [Select ID,First_Name__c, Last_Name__c,Zipcode__c, Contact__c From Voter_File_TX__c])
        {
                    if(mp_VoterFile==null)
                        mp_VoterFile = new Map<String,Voter_File_TX__c>();
            
            mp_VoterFile.put(VoterFile.First_Name__c +''+VoterFile.Last_Name__c +''+VoterFile.Zipcode__c,VoterFile);

 
                    }
        
        for(Contact ContactList : Trigger.new)
    {
        if(mp_VoterFile!=null && mp_VoterFile.containsKey(ContactList.FirstName+''+ ContactList.LastName+''+ ContactList.MailingPostalCode))

        {

       mp_VoterFile.get(ContactList.FirstName +''+ ContactList.LastName +''+ ContactList.MailingPostalCode).Contact__c = ContactList.id;

}

}
 
if(mp_VoterFile!=null && mp_VoterFile.values()!=null)
        update mp_VoterFile.values();

    }
}
}



 

I was able to write two apex triggers that connect two objects(Contacts and a Custom Object) via a lookup field when they have the same first name, last name, and zip code. This was done in my sandbox environment and I was able to get this working perfectly there. I then, with help through the moudles and references, was able to write a small sample test class in order to have this deployed in my production environment, but i am only able to get 24 percent coverage. 

Please help as I am stuck, below is one of my triggers and my test class. 

 

trigger VoterID2Contact on Voter_File_TX__c (before insert,before update,after insert,after update) 

{ if(checkRecursive.runOnce){ return;}
{
    Set<String> set_Str = new Set<string>();
    Map<String,Contact> mp_ContactID;
    
    if(Trigger.isAfter && Trigger.isUpdate)
    {
        for(Contact ContactID : [Select ID,FirstName, LastName,MailingPostalCode, Voter_File_ID__c From Contact])
        {
                    if(mp_ContactID==null)
                        mp_ContactID = new Map<String,Contact>();
            
            mp_ContactID.put(ContactID.FirstName +''+ContactID.LastName +''+ContactID.MailingPostalCode,ContactID);

 
                    }
        
        for(Voter_File_TX__c VoterList : Trigger.new)
    {
        if(mp_ContactID!=null && mp_ContactID.containsKey(VoterList.First_Name__c+''+ VoterList.Last_Name__c+''+ VoterList.Zipcode__c))

        {

       mp_ContactID.get(VoterList.First_Name__c +''+ VoterList.Last_Name__c +''+ VoterList.Zipcode__c).Voter_File_ID__c = VoterList.id;

}

}
 
if(mp_ContactID!=null && mp_ContactID.values()!=null)
        checkRecursive.runOnce = true;
        update mp_ContactID.values();

    }
}
}

and this is my test class
 
@isTest
public class TestClass 
{
    static testMethod void testMethod1()
    {
        
        Voter_File_TX__c vf = new Voter_File_TX__c();
        vf.First_Name__c ='Test';
        vf.Last_Name__c ='Test';
        vf.RNC_ID__c = 'Test';
        vf.Zipcode__c = 'Test'; 
        
         insert vf;

        Contact cont = new Contact();
        cont.FirstName ='Test';
        cont.LastName = 'Test';
        cont.RNC_ID__c = 'Test';
        cont.MailingPostalCode = 'test';
    
        insert cont;
        
        vf.First_Name__c = cont.FirstName ;
        vf.Last_Name__c = cont.LastName ;
        vf.Zipcode__c = cont.MailingPostalCode ;
        vf.RNC_ID__c = cont.RNC_ID__c ;
        vf.Contact__c = cont.Id ;
        
        cont.FirstName = vf.First_Name__c ;
        cont.LastName = vf.Last_Name__c ;
        cont.MailingPostalCode = vf.Zipcode__c;
        cont.RNC_ID__c = vf.RNC_ID__c ;
        
       
    }

}

 
I was able to write 2 triggers for two different custom objects TGA_Email_List__c and Voter_File__c. Both triggers look for a match between the two custom objects, of first name, last name, and zipcode and if a match found then one trigger auto populates the lookup field of Voter_ID_del__c on TGA_Email_List custom object, while the other trigger auto populates the look up field of Email_ID_del__c on the Voter_File__c object. 

These triggers work great if I run them indvidually, having only one of them active. However, when I have both of the triggers active they run into a recusrvie error because both are set to run when a reocrd in that object is update or created, thus creating a constant error and rescursive loop that goes on forever. Both Triggers are below.

Trigger 1:
trigger EmailtoVoterFile on TGA_Email_List__c (before insert,before update,after insert,after update)
{ if(checkRecursive.runOnce())
{
    Set<String> set_Str = new Set<string>();
    Map<String,Voter_File__c> mp_voterfileObj;
    
    if(Trigger.isAfter && Trigger.isUpdate)
    {
        for(Voter_File__c voterfileobj : [Select ID,First_Name__c, Last_Name__c,ZipCode__c, Email_ID_del__c From Voter_File__c])
        {
                    if(mp_VoterfileObj==null)
                        mp_VoterFileObj = new Map<String,Voter_File__c>();
            
            mp_VoterFileobj.put(voterfileobj.First_Name__c +''+voterfileobj.Last_Name__c +''+voterfileobj.Zipcode__c,voterfileobj);

 
                    }
        
        for(TGA_Email_List__c TGAEmailListobj : Trigger.new)
    {
        if(mp_VoterFileObj!=null && mp_Voterfileobj.containsKey(TGAEmailListobj.First_Name__c +''+ TGAEmailListobj.Last_Name__c +''+ TGAEmailLIstobj.Zipcode__c))

        {

       mp_Voterfileobj.get(TGAEmailListobj.First_Name__c +''+ TGAEmailLIstobj.Last_Name__c +''+ TGAEmailListobj.Zipcode__c).Email_ID_del__c = TGAEmailListobj.id;

}

}
 
if(mp_VoterFileObj!=null && mp_VoterFileObj.values()!=null)
        update mp_VoterFileObj.values();

    }
}
}

Trigger 2:
trigger VoterIDUpdate on Voter_File__c (before insert,before update,after insert,after update) 
{ if(checkRecursive.runOnce())
{
    Set<String> set_Str = new Set<string>();
    Map<String,TGA_Email_List__c> mp_EmailList;
    
    if(Trigger.isAfter && Trigger.isUpdate)
    {
        for(TGA_Email_List__c EmailList : [Select ID,First_Name__c, Last_Name__c,ZipCode__c, Voter_ID_del__c From TGA_Email_List__c])
        {
                    if(mp_EmailList==null)
                        mp_EmailList = new Map<String,TGA_Email_List__c>();
            
            mp_EmailList.put(EmailList.First_Name__c +''+EmailList.Last_Name__c +''+EmailList.Zipcode__c,EmailList);

 
                    }
        
        for(Voter_File__c VoterID : Trigger.new)
    {
        if(mp_EmailList!=null && mp_EmailList.containsKey(VoterID.First_Name__c +''+ VoterID.Last_Name__c +''+ VoterID.Zipcode__c))

        {

       mp_EmailList.get(VoterID.First_Name__c +''+ VoterID.Last_Name__c +''+ VoterID.Zipcode__c).Voter_ID_del__c = VoterID.id;

}

}
 
if(mp_EmailList!=null && mp_EmailList.values()!=null)
        update mp_EmailList.values();

    }
}
}

I then wrote a class and included a code in the triggers that would solve this issue and have it only run once if it was recusrive, however when I did this then and activated both triggers none of the fields were being auto populated if a match was found, also there was no error being thrown out. 

Class:
public class checkRecursive {
    private static boolean run = true;
    public static boolean runOnce(){
    if(run){
     run=false;
     return true;
    }else{
        return run;
    }
    }  
}

My question is how do I get this to work so that I can have both of lookup fields auto populate based on a match on both custom objects, while also not getting a recuring error. 

Please, help I am stuck, Thanks!
 
Hello, I am trying to set up a connection where I can connect two custom objects that have the same custom field values such as first, last name, and/or zipcode. If matching records based off of these custom feilds are found then the connection needs to autopopulate the lookup field that points back to each objecet, which in this case is just the standard Salesforce generated ID of each record in their respective custom object.

Technically, what I want to happen is for there to be a scan of all records in one object and look for any matches based off one or multiple custom fields in another object, after that have an automation that will happen to connect those matching records.

I tired doing this through the process builder, and the workflow but I had no luck, I was then told by techical support that Apex Trigger would be the only way to do this. 

Please help, also If I am unclear please let me know. 

Thanks. 
I have to pull up lead or contact info in HTML email template.
Can someone explain me what's this mean %%first_name%% , %%view_online%%
%%Oraganization%%

I need to replace value in Salesforce with above info.