SFDCで大容量CSVアップロード作ってみました。

このエントリーをはてなブックマークに追加
こんにちわ。R&D部のishikawaです。

去年の秋に入社し、今年の始めまで、Salesforceで社内販売管理システムの開発をしていました。
Salesforceでの開発未経験、社内業務の知識0、会計知識も乏しい中、
開発をやれたのも、管理部を始めとして協力していただいたみなさまのおかげです。

ありがとうございますm(_ _)m

Salesforceはあまり日本語の詳しい解説が載ったサイトがなく、
英語のサイトとにらめっこすることが多いです。
今回はそんな私のようなお困りの方々のために、大容量CSVファイルアップロード
作成体験談を書かせていただきます。

経緯


月一回の事務作業として、他システムから取得した集計データのCSVファイルを
Salesforceに取り込んでいます。
ただ取り込むだけだったら、データローダというSalesforceのツールを使って
取り込めばいいのですが、
その前にSalesforceの他のデータと突合させて、
いるデータいらないデータを振り分け、加工しなければなりません。
その作業を毎月担当者が30分〜1時間かけて行っておりました。

本来なら、CSVファイルを用いず、直接APIを使ってやり取りしたいところなのですが、
大人の事情により(笑)、現状はCSVファイルでの取り込みを行っております。

機能要件


  • VisualforceページでローカルのCSVを選択・アップロード
  • Salesforceのオブジェクトと突合させて、加工して、保存
  • データ件数は10,000件程度を想定

ガバナ制限?


Salesforceにはガバナ制限と呼ばれる制約条件があります。
クエリの発行可能総数などなど。
そのため、大容量のデータを取り扱った処理を行うにあたり注意が必要になります。
今回はBatchクラスを作成し、その制限を回避することにしました。


とりあえず作ってみる


1. APEXクラス+Visualforceページを用意。




    
        
            
                
            
        
        
            
        
     



public class CSVUploader {

    public Blob file { get; set; }

    public Pagereference readFile() {
     CSVParser.Parser parser = new CSVParser.XXXParser();
     BatchCSVUploader batch = new BatchCSVUploader(file, parser);
                
        return null;
    }
}

こんな感じのページが出来上がります。↓





2. 取り込み対象のCSVファイルは2種類あり、それぞれ異なる処理を行いたいため、
  Parserを用意して、バッチのコンストラクタに渡すようにしました。


public class CSVParser {
	
	public interface Parser {		
		void create(List> csvLines);
	}
	
	public class XXXParser implements Parser {
		
		public void create(List>> csvLines) {
                    // 処理
		}
	}
}

3. Batchクラスを作成・・・あれ?


Stringクラスのsplitメソッドで
改行コードで分割し、行単位のリストを作ろうとしたところ、エラー発生。
"Regex too complicated" error

エラーで検索したところ、参考となりそうなサイトを発見。
http://developer.financialforce.com/customizations/importing-large-csv-files-via-batch-apex/

BatchクラスからCSVIteratorを利用して行読み込み処理を行うようにしました。
ちなみに英語は読めないので、雰囲気だけ真似てますw
global with sharing class BatchCSVUploader implements Database.Batchable, Database.Stateful {

    private String csvFile;
    private CSVParser.Parser parser;
    private static final String CRLF = '\n';
    public BatchCSVUploader(Blob file, CSVParser.Parser parser){
        this.csvFile = file.toString();
        this.parser = parser;
    }
    global Iterable start(Database.batchableContext batchableContext) { 
       return new CSVIterator(csvFile, CRLF);
    }
    global void execute(Database.BatchableContext batchableContext, List scope) {
        List>>> csvLines = new List>>>();
        for(String row : scope) {
           csvLines.add(row.split(','));
        }
        parser.create(csvLines);
   }
   global void finish(Database.BatchableContext batchableContext){}
   
}
global with sharing class CSVIterator implements Iterator, Iterable {
   private String m_CSVData;
   private String m_introValue;
   public CSVIterator(String fileData, String introValue)
   {
      m_CSVData = fileData;
      m_introValue = introValue; 
   }
   global Boolean hasNext() {
      return m_CSVData.length() > 1 ? true : false;
   }
   global String next() {
      String row = m_CSVData.subString(0, m_CSVData.indexOf(m_introValue));
      m_CSVData = m_CSVData.subString(m_CSVData.indexOf(m_introValue) + m_introValue.length(),m_CSVData.length());
      return row;
   }
   global Iterator Iterator() {
      return this;
   }
}

>>> なんとかうまく動きました。




まとめ


CSVデータを取り込むために、Excelをごにょごにょして、
時間をかけて行っていた作業をなくすことができました。

が、やっぱりAPIでやりたい・・・と思いましたw
その際は、ご協力宜しくお願い致しますm(_ _)m
次の記事
« Prev Post
前の記事
Next Post »
Related Posts Plugin for WordPress, Blogger...