【Apex】親子関係のレコード挿入処理が綺麗に書けるライブラリ

photo of grass field カテゴリーなし
Photo by Alexandr Podvalny on Pexels.com

Apex では、DMLを for ループの中に書けない(ガバナ制限対策)ため、for ループを使った
親と子のレコードの作成→親子関係の設定→DML操作
のような処理を書くのが面倒です。

しかし、fflib_SObjectUnitOfWork クラスを使うことで、シンプルで理解しやすいコードを書くことができます。

通常の書き方

親子関係のレコードを同時に作成する場合、通常は以下のような書き方になります。

  1. 親レコードの作成
  2. 親レコードの挿入(このタイミングでIDが設定される)
  3. 子レコードの主従(参照)関係に、親レコード.ID の値を設定する
  4. 子レコードの挿入

コードで書くとこんな感じです。

Parent p = new Parent(Name = 'Parent1');
insert p;
Child c = new Child(Name = 'Child1');
c.Parent__c = p.Id;
insert c;

このように親レコードと子レコードを1つずつ作る場合は簡単なのですが、このような組み合わせを大量に作るときは工夫が必要になります。

問題点

例えば、単純にこんな書き方をするとガバナ制限に引っかかります。

for(Integer i=0; i<1000; i++){
    Parent p = new Parent(Name = 'Parent' + i);
    insert p;
    Child c = new Child(Name = 'Child' + i);
    c.Parent__c = p.Id;
    insert c;
}

なので親子の関係性を List に一時保存した上で、親レコードの保存後に主従関係を改めて設定する、などの工夫が必要です。

List<Parent> pList = new List<Parent>();
List<Child> cList = new List<Child>();
for(Integer i=0; i<1000; i++){
    Parent p = new Parent(Name = 'Parent' + i);
    pList.add(p);
    Child c = new Child(Name = 'Child' + i);
    cList.add(c);
}
insert pList;

for(Integer i=0; i<1000; i++){
    cList[i].Parent__c = pList[i].Id;
}
insert cList;

これはまだ単純な例ですが、1つの親に複数の子だったり、親-子-孫まで1度に作成したりするとさらに面倒な書き方になります。

fflib_SObjectUnitOfWork クラスの利用

Apex オープンソースライブラリである fflib_SObjectUnitOfWork クラスを使うと、もっと読みやすいコードになります。

具体的には、fflib_SObjectUnitOfWork のインスタンスを作成した上で、親子の関係性をそのインスタンスに登録していきます。
そして、最後に .CommitWork() メソッドを実行すると DMLを一括処理化して実行し、親子関係の設定とデータベース登録を上手いこと1度にやってくれる訳です。

これでさっきの例も1度の for ループに処理が収まり、読みやすいコードになりました。

fflib_SObjectUnitOfWork uow = new fflib_SObjectUnitOfWork(
    new Schema.SObjectType[] {
        // 親子関係の順で書く
        Parent.SObjectType,
        Child.SObjectType
    }
);

for(Integer i=0; i<1000; i++){
    Parent p = new Parent(Name = 'Parent' + i);
    uow.registerNew(p);
    Child c = new Child(Name = 'Child' + i);
    uow.registerNew(c, Child.Parent__c, p);
}

// DML操作を一括処理化して実行
uow.CommitWork();

コメント

タイトルとURLをコピーしました