「Salesforce」ApexバッチでDelete&Insertしたときのメモ

ヘルプで頼まれたため、要件定義や設計思想に関して詳しい経緯が分かっていないのですが。

とあるオブジェクト「Hoge__c」は「キャンペーンメンバオブジェクト」のバックアップといいますか。
内容をコピーし、レコード件数を一致させた状態にしたいというお話がありました。


最初は単純に
・キャンペーンメンバをデータローダでexport⇒加工してHoge__cに入れる。
・その後、キャンペーンメンバの追加・更新・削除・ゴミ箱復活のトリガで、Hoge__cを追加・更新・削除・ゴミ箱復活すればいいかな?
なんて思っていたのですが、
・取引先責任者のマージ機能でキャンペーンメンバが変更されたときは、トリガが動いてくれない。
ということが分かりました。
ですので、リアルタイム同期しようとしたこの案は却下。

次に、リアルタイム同期は難しいということを顧客に相談したところ、定時で更新されていればOKという話になりました。
Apexスケジュール起動&Apexバッチを使用し、キャンペーンメンバの追加・更新・削除を更新日付、ゴミ箱検索で判断し差分を「Hoge__c」に反映させればどうか?
という案が発生したので、作ってみたところ、
「キャンペーンメンバは削除したときゴミ箱に入らずに削除される。」
という仕様と分かり、削除分の差分が取れないことが判明。


最終的に、「Hoge__c」を全件Deleteし、キャンペーンメンバの全件をinsertするということに落ち着きました。
ただし、顧客の都合上もあってコマンドラインのスケジュールによるデータローダ起動はありえない。
ということで、Apexスケジュール起動&Apexバッチでdelete&insert。
deleteのバッチを動かして、終了処理にて、数分後にinsertのバッチのスケジューリングをするという手法です。
Apexバッチのスケジュールジョブが溜まるのを防ぐため、一度スケジュールを消してから作るという方針になっています。

global with sharing class Scheduler_Delete implements Schedulable{

    /** バッチ実行サイズ。*/
    private final Integer BATCH_SIZE = 2000;

    /** スケジュール起動メソッド*/
    global void execute(SchedulableContext sc) {

        Batch_Delete b = new Batch_Delete();
        Database.executeBatch(b, BATCH_SIZE);
    }
}




/**
 * イベント参加履歴の全件削除をするバッチです。
 */
 global with sharing class Batch_Delete implements Database.Batchable<sObject>, Database.Stateful{

    //-------------------------------//
    //  クラス変数
    //-------------------------------//
    /** バッチの繰り返しとなるクエリ */
    private String query;


    /**
     * コンストラクタ
     */
    global Batch_Delete(){

        //ホゲを検索します。
        query = 'SELECT id FROM Hoge__c ';
    }

    /**
     * バッチの開始位置
     */
    global Database.QueryLocator start(Database.BatchableContext BC){
        return Database.getQueryLocator(query);
    }


    /**
     * バッチの処理
     */
    global void execute(Database.BatchableContext BC, List<Hoge__c> scope){
        delete scope;
        //ゴミ箱の削除
        Database.emptyRecycleBin(scope);
    }


    /**
     * バッチの終了処理
     */
    global void finish(Database.BatchableContext BC){

        //過去のinsertのスケジュールの削除
        List<CronTrigger> cronTriggerList =
            [ SELECT Id,
                     CronJobDetail.Name
              FROM   CronTrigger
              WHERE  CronJobDetail.JobType = '7'];

        for(CronTrigger ct : cronTriggerList){

            if(ct.CronJobDetail.Name.contains('insert')){
                System.abortJob( ct.Id );
            }
        }




        //次のスケジュールを設定
        Datetime t = Datetime.now();
        t = t.addMinutes(5);
        integer year = t.year();
        integer month = t.month();
        integer day = t.day();
        integer hour = t.hour();
        integer minute = t.minute();
        integer second = t.second();
        String jobName = 'insert' + String.valueOf(t);
        String Cron = second + ' ' + minute + ' ' + hour + ' ' + day + ' ' + month + ' ? ' + year + '-' + year;
        System.debug(Cron);
        System.schedule(jobName, Cron, new Scheduler_insert());


    }
}


/**
 * イベント参加履歴の登録・更新スケジュール起動です。
 */
global class Scheduler_insert implements Schedulable{

    /** バッチ実行サイズ。*/
    private final Integer BATCH_SIZE = 2000;

    /** スケジュール起動メソッド*/
    global void execute(SchedulableContext sc) {

        Batch_insert b = new Batch_insert();
        Database.executeBatch(b, BATCH_SIZE);
    }
}



/**
 * イベント参加履歴の登録・更新バッチです。
 */
global with sharing class Batch_insert implements Database.Batchable<sObject>, Database.Stateful{

    //-------------------------------//
    //  クラス変数
    //-------------------------------//
    /** バッチの繰り返しとなるクエリ */
    private String query;

    /**
     * コンストラクタ
     */
    global Batch_insert(){

        //イベント参加履歴の元となる、キャンペーンメンバを検索します。
        query = 'SELECT id, '
              +        'ContactId, '
              +        'Status, '
              +        'Campaign.Name '
              + 'FROM   CampaignMember ';
    }



    /**
     * バッチの開始位置
     */
    global Database.QueryLocator start(Database.BatchableContext BC){
        return Database.getQueryLocator(query);
    }


    /**
     * バッチの処理
     */
    global void execute(Database.BatchableContext BC, List<CampaignMember> scope){

        //登録用のリスト生成
        List<Hoge__c> insertList = new List<Hoge__c>();

        //ホゲの登録データを作成します。
        for(CampaignMember rec : scope){
            Hoge__c hogeObject = newHoge__c();

            hogeObject.Contact__c = rec.Contactid;                                //取引先責任者
            hogeObject.Attendance__c = rec.Status;                                //参加状況
            hogeObject.CampaignMemberID__c = String.valueOf(rec.id);    //キャンペーンメンバID
            hogeObject.CanpaignName__c = rec.Campaign.Name;                    //キャンペーン名
            insertList.add(hogeObject);
            }

            insert insertList;
    }


    /**
     * バッチの終了処理
     */
    global void finish(Database.BatchableContext BC){

    }
}

関連記事


--------------------------------------------------------------------------------------

コメントの投稿

非公開コメント

このブログについて
  • 全記事一覧(時間順)
  • このブログについて
  • 私のプロフィール
  • 当ブログで扱っている動画について
  • 記事違いなコメントのお返事

  • カテゴリー
    twitter
    カレンダー
    04 | 2017/05 | 06
    - 1 2 3 4 5 6
    7 8 9 10 11 12 13
    14 15 16 17 18 19 20
    21 22 23 24 25 26 27
    28 29 30 31 - - -
    Amazon
    でたらめな当ブログにぴったりな商品を自動で表示するみたいです。



    月別アーカイブ
    プロフィール

    たづみ

    Author:たづみ
    ・1981年生まれの男
    ・もう少し詳細なプロフィールはこちらで

    最新コメント
    アクセスランキング
    [ジャンルランキング]
    日記
    1035位
    アクセスランキングを見る>>

    [サブジャンルランキング]
    会社員・OL
    212位
    アクセスランキングを見る>>