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
Akhil TyagiAkhil Tyagi 

Import bulk contact records from csv using vf page

I want to import bulk contact records to insert from csv file using vf page.
I am able to insert around 1000 records but if there are than 1000 records, i get an error of 'time limit exceeded'.

Here is my VF Page:
<apex:page controller="UploadCSVController">
    <h1 style="font-size:30px"><center>CSV Uplaod Page</center></h1><br/><br/>

    <apex:form id="idForm">
        <apex:pageMessages /><br/><br/>

        <apex:pageBlock tabStyle="Contact" id="idInputBlock">
            <p style="height:13px; font-size:13px"><b>Set the first column of the CSV file as LastName Field:</b></p><br/>
            <apex:inputFile value="{! fileBody}" fileSize="{! fileSize}" fileName="{! fileName}" accept=".csv" contentType="text/csv" id="idInputFile"></apex:inputFile>                 <!-- Input File -->
            <apex:commandButton value="Upload File" action="{! ReadFromFile}" onclick="document.getElementById('actionStatusUP').style.display = 'inline';" />  <!-- Upload Button to upload file -->
            <img src="/img/loading.gif" style="display:none" id="actionStatusUP" />                    
            <apex:pageBlockButtons location="bottom" >                                                                                                          <!-- Save Button to insert the records -->
                <apex:commandButton value="Save" action="{! save}" rendered="{! reVariableSave}" onclick="document.getElementById('imageSV').style.display = 'inline';" />
                <img src="/img/loading.gif" style="display:none" id="imageSV" />
            </apex:pageBlockButtons>
        </apex:pageBlock>

        <apex:pageBlock rendered="{! reVariableBlock}" id="idTable">
            <apex:pageBlockSection collapsible="false" columns="2" >
                <p><b>Total Records in CSV File:&nbsp;</b></p>
                <apex:outputText value="{! totalRecords}" style="color:black" />
                <p><b>Number of Records Successfully inserted:&nbsp;</b></p>
                <apex:outputText value="{! insertedRecords}" style="color:green" />
                <p><b>Number of Failed Records:&nbsp;</b></p>
                <apex:outputText value="{! failedRecords}" style="color:red" />
            </apex:pageBlockSection><br/>
            <center><p style="color:dodgerblue;font-size:25px"><b>Details of the inserted records</b></p></center><br/><br/>
            <apex:pageBlockTable value="{! contactsList}" rendered="{! reVariable}" var="con" >                                                           <!-- Table to display details of inserted records -->
                <apex:repeat value="{! fieldNamesList}" var="fld" >
                    <apex:column value="{! con[fld]}" />
                </apex:repeat>
            </apex:pageBlockTable>
        </apex:pageBlock>
        
    </apex:form>
</apex:page>
Here is my controller code:
public with sharing class UploadCSVController {

    //Public Variables----------------------------------------------------------------------------------------------------------------------------------------------
    public transient Blob    fileBody{ get; set; }                              //fileBody
    public transient Integer fileSize{ get; set; }                              //fileSize
    public transient String  fileName{ get; set; }                              //fileName
    public List<Contact>     contactsList{ get; set; }                          //List of inserted contacts
    public List<String>      fieldNamesList{ get; set; }                        //List of fields in Contact Object's fields which are avaiable in CSV
    public Boolean           reVariableSave{ get; set; }                        //Variable to render Save Button
    public Boolean           reVariableBlock{ get; set; }                       //Variable to render PageBlock with inserted record details
    public Boolean           reVariable{ get; set; }                            //Variable to render Record Details Table    
    public Integer           totalRecords{ get; set; }                          //Total number of records in CSV File
    public Integer           insertedRecords{ get; set; }                       //Number of records successfully inserted
    public Integer           failedRecords{ get; set; }                         //Number of failed records

    //Private Variables----------------------------------------------------------------------------------------------------------------------------------------------
    String fileBodyAsString = '';                                               //String value of file Body
    String header           = '';

    //Constructor----------------------------------------------------------------------------------------------------------------------------------------------------
    public UploadCSVController(){
        contactsList        = new List<SObject>();
        fieldNamesList      = new List<String>();
        reVariableSave      = false;
        reVariableBlock     = false;
        reVariable          = false;
        totalRecords        = 0;
        insertedRecords     = 0;
        failedRecords       = 0;    
    }

    //Method to check file size and whether the file body is readable------------------------------------------------------------------------------------------------
    public void ReadFromFile(){
        reVariableBlock = false;
		if(fileSize < 3280760 && fileName.substringAfterLast('.').equalsIgnoreCase('csv')){
            try{
                fileBodyAsString = fileBody.toString();
                ReadCSVFile();
            }
            catch(exception e){
                ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'Error reading CSV file'));
            }
        }
        else{
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'No File Chosen or,'));
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'File Size greater than 50 KB or,'));
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'File is not of CSV type'));
        }
    }

    //Method to read the file and create a contact list which will be inserted and check exceptions in CSV file------------------------------------------------------
    private void ReadCSVFile(){
        if(fileBodyAsString.length() > 100000){
            header = fileBodyAsString.substring(0, 2000).split('\n')[0];
        }
        else{
            header = fileBodyAsString.split('\n')[0];
        }
        fileBodyAsString = fileBodyAsString.substringAfter('\n');

        contactsList.clear();
        fieldNamesList.clear();
        for(String str : header.split('\n')[0].split(',')){
            fieldNamesList.add(str.trim());
        }
        String                      contactDetails      = '';
        Map<string, SObjectField>   fieldNamesMap       = Schema.getGlobalDescribe().get('Contact').getDescribe().fields.getMap();

        if(fieldNamesList[0].equalsIgnoreCase('LastName')){
            Contact con             = new Contact();
            Integer flag            = 0; 
            while( !String.isEmpty(fileBodyAsString)){                                                                 //Itereation over each contact
                if(fileBodyAsString.length() > 100000){
                    contactDetails = fileBodyAsString.substring(0, 100000).split('\n')[0];
                }
                else{
                    contactDetails = fileBodyAsString.split('\n')[0];
                }
                fileBodyAsString = fileBodyAsString.substringAfter('\n');
                String lastnameValue = contactDetails.substringBefore(',').trim();
                for(Integer j=0; j<fieldNamesList.size(); j++){                                                                 //Iterating over the fields & assigning value to them for each contact 
                    Schema.DisplayType fieldType = fieldNamesMap.get(fieldNamesList[j]).getDescribe().getType();
                    if( fieldType == Schema.DisplayType.DATE ){              //Setting value of fields which are of Date Type
                        try{
                            con.put(fieldNamesList[j].trim(), Date.valueOf(contactDetails.substringBefore(',').trim()));
                        }
                        catch(Exception e){
                            flag = 1;
                            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Empty ' + fieldNamesList[j].trim() + ' field or Date is not in format \"YYYY-MM-DD\" for record with LastName = ' + lastnameValue));
                        }
                    }
                    else if( fieldType == Schema.DisplayType.DATETIME ){ //Setting value of fields which are of DateTime Type
                        try{
                            con.put(fieldNamesList[j].trim(), Datetime.valueOf(contactDetails.substringBefore(',').trim()));
                        }
                        catch(Exception e){
                            flag = 1;
                            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Empty ' + fieldNamesList[j].trim() + ' field or DateTime is not in format \"YYYY-MM-DD HH:MM:SS\" for record with LastName = ' + lastnameValue));
                        }
                    }
                    else if( fieldType == Schema.DisplayType.BOOLEAN ){  //Setting value of fields which are of Boolean Type
                        if(contactDetails.substringBefore(',').trim().equalsIgnoreCase('true') || contactDetails.substringBefore(',').trim().equalsIgnoreCase('false') || contactDetails.substringBefore(',').trim() == ''){
                            con.put(fieldNamesList[j].trim(), Boolean.valueOf(contactDetails.substringBefore(',').trim()));
                        }
                        else{
                            flag = 1;
                            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,  'Acceptable value for ' + fieldNamesList[j].trim() + ' field is \"TRUE/FALSE\" for record with LastName = ' + lastnameValue));
                        }
                    }
                    else if( fieldType == Schema.DisplayType.TEXTAREA ){ //Setting value of fields which are of TextArea Type
                        if(contactDetails.left(1) != '\"'){                                                                 //Setting value of fields which are of TextArea Type with comma
                            con.put(fieldNamesList[j].trim(), contactDetails.substringBefore(',').trim());
                        }
                        else{                                                                                               //Setting value of fields which are of TextArea Type without comma
                            con.put(fieldNamesList[j].trim(), contactDetails.substringBetween('\"', '\"') .trim());
                            contactDetails = contactDetails.substringAfter('\"').substringAfter('\"');
                        }
                    }
                    else{                                                                                                   //Setting value of all other type of fields
                        try{
                            con.put(fieldNamesList[j].trim(), contactDetails.substringBefore(',').trim());
                        }
                        catch(Exception e){
                            flag = 1;
                        }
                    }
                    contactDetails = contactDetails.substringAfter(',');
                }
                contactsList.add(con);
                con = new Contact();
            }                  
            if(flag != 1){                                                                                                  //If there is no exception, show Save button
                reVariableSave = true;
                ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO,  'Click Save Button to insert the Records '));
            }
        }
        else{
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,  'First Column in CSV file is not LastName. Set the first column in CSV file as LastName'));
        }
    }

    //Save method to insert the Contact Recods and counting inserted records and failed records----------------------------------------------------------------------
    public Pagereference save(){
        reVariableBlock = true;
        Database.SaveResult[] srList = Database.insert(contactsList, false);
        contactsList.clear();
        Set<Id> savedContactIdSet = new Set<Id>();
        totalRecords    = 0;
        insertedRecords = 0;
        failedRecords   = 0;
        for (Database.SaveResult sr : srList) {
            ++totalRecords;
            if (!sr.isSuccess()) {
                ++failedRecords;               
                for(Database.Error err : sr.getErrors()) {
                    ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,  err.getStatusCode() + ': ' + err.getMessage() + ' for Record at Line Number: ' + (totalRecords + 1)));
                }
            }
            else{
                ++insertedRecords;
                savedContactIdSet.add(sr.getId());
            }
        }
        contactsList = Database.query('SELECT ' + header + ' FROM Contact WHERE Id in :savedContactIdSet');
        if(contactsList.size() > 0 && contactsList.size()<400){
            reVariable = true;
        }
        return null;
    }
}
Please help me with the solution on how to insert more than 10,000 reocrds without hitting the time limit exceed limt.
 
Dushyant SonwarDushyant Sonwar
The Only solution for this problem would be to break the csv file into smaller chunks using apex code , so it can process easily otherwise directly processing 10,000 records(approx 1Mb) file will lead to either view state , CPU Time limit or apex heap size error errors.