Skip to content

Instantly share code, notes, and snippets.

@martyychang
Created December 19, 2014 06:21
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save martyychang/e133652e35bc6bd89ac3 to your computer and use it in GitHub Desktop.
Save martyychang/e133652e35bc6bd89ac3 to your computer and use it in GitHub Desktop.
Reference implementation for a batch Apex class that uses CSVReader to parse CSV data and then insert records
/*
* Batchable, schedulable job for importing data contained in uploaded
* CSV files for consumption. This job is created for demonstration purposes
* only, and it is not intended to be used in a production environment.
*
* The job looks for CSV files uploaded as Document records with the following
* convention for the Document Name:
*
* {!ObjectAPIName}-import.csv
*
* For each file found, the job will assume that the first row contains
* field names, and the remaining rows contain values.
*
* Again, for demonstration purposes this job only inserts new records. It does
* not update any existing records.
*
* @author Marty Y. Chang
* @version Winter '15
*/
global class ImportCSVJob implements Database.Batchable<SObject>, Schedulable {
/*
* Delimiter used for splitting a given filename's short name (without
* the file extension)
*/
global static final String FILENAME_PART_DELIMITER = '-';
/*
* Delimiter used for splitting a given filename's extension from the
* simple name, specified with the expectation of using this delimiter
* with String.split()
*/
global static final String FILENAME_EXTENSION_DELIMITER = '\\.';
/*
* Default constructor
*/
global ImportCSVJob() {
}
/*
* Parse the first file in the list of what are assumed to be Document
* records.
*
* @param context The batch context
* @param records The list of records to be processed in this batch
*/
global void execute(
Database.BatchableContext context, List<SObject> records) {
// Cast the first record as a Document object
Document theDocument = (Document)records.get(0);
System.debug('theDocument: ' + theDocument);
// Read the document's body as CSV records
List<List<String>> csvRecords =
CSVReader.readIETFRFC4180CSVFile(theDocument.Body);
System.debug('csvRecords: ' + csvRecords);
// Figure out the object name based on the Document Name
String simpleFilename =
theDocument.Name.split(FILENAME_EXTENSION_DELIMITER).get(0);
String objectName =
simpleFilename.split(FILENAME_PART_DELIMITER).get(0);
// Import the given data into the object using the parser
import(csvRecords, objectName);
}
/*
* Execute this scheduled job as a batch job
*
* @param context The schedule context
*/
global void execute(SchedulableContext context) {
Database.executeBatch(this, 1);
}
/*
* Do something cool now that the job is finished
*
* @param context The batch context
*/
global void finish(Database.BatchableContext context) {
}
/*
* @return the String query that will be executed to retrieve
* Document records that need to be processed
*/
global static String getDocumentQuery() {
return 'SELECT Id, Name, Body FROM Document ' +
'WHERE Name LIKE \'%import.csv\'';
}
/*
* Import CSV rows as records into a given object
*
* @param records a list of CSV records, each of which is expected
* to be a list of String values. The first record
* should be the list of field names.
* @param objectName
*/
global static void import(
List<List<String>> csvRecords, String objectName) {
// Read the first row as field names
List<String> fieldNames = csvRecords.remove(0);
// Continue with the import
import(csvRecords, objectName, fieldNames);
}
/*
* Import CSV rows as records into a given object
*
* @param records a list of CSV records, each of which is expected
* to be a list of String values
* @param objectType
* @param fieldNames
*/
global static void import(
List<List<String>> csvRecords, SObjectType objectType, List<String> fieldNames) {
System.debug('csvRecords: ' + csvRecords);
System.debug('objectType: ' + objectType);
System.debug('fieldNames: ' + fieldNames);
// Initialize the list of records to insert
List<SObject> newRecords = new List<SObject>();
// Read each row and parse the row as value to insert
while (csvRecords.size() > 0) {
// Initialize the new record
SObject newRecord = objectType.newSObject();
// Read the CSV values
List<String> values = csvRecords.remove(0);
// Read each value, matching it up to the correct field
// based on the position of the value in the row
if (values.size() > 0) {
for (Integer i = 0; i < fieldNames.size(); i++) {
String fieldName = fieldNames.get(i);
String fieldValue = values.get(i);
newRecord.put(fieldName, fieldValue);
}
// Enqueue the record to be created
newRecords.add(newRecord);
}
}
// Insert the list of records
insert newRecords;
}
/*
* Import CSV rows as records into a given object
*
* @param records a list of CSV records, each of which is expected
* to be a list of String values
* @param objectName
* @param fieldNames
*/
global static void import(
List<List<String>> csvRecords, String objectName, List<String> fieldNames) {
// Figure out the object type to use for intantiating new records
SObjectType objectType =
Schema.getGlobalDescribe().get(objectName);
// Continue with the import
import(csvRecords, objectType, fieldNames);
}
/*
* @param context The batch context
* @return the QueryLocator that will go through all of the documents
* that need to be processed as CSV files
*/
global Database.QueryLocator start(Database.BatchableContext context) {
return Database.getQueryLocator(getDocumentQuery());
}
}
@swarna22
Copy link

swarna22 commented Jul 6, 2015

Hi i am getting the below error
Error: Compile Error: Variable does not exist: CSVReader at line 58 column 13

@tmowbrey
Copy link

tmowbrey commented Sep 4, 2015

@jayasree-sathyasairam
Copy link

The query you have used contains "%import.csv". In salesforce how to find this file. I have a sample file in my local, How this query will find this data? Could you please explain?

@martyychang
Copy link
Author

Hi @jayasree-sathyasairam this gist is pretty old. The example uses the Document object, which is for the Documents feature in Salesforce Classic. If you're interested in this legacy object, you can find more technical details in the developer docs on the Document object and the ERD.

For a more current implementation you should probably replace Document records with Salesforce Files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment