Apex では、DMLを for ループの中に書けない(ガバナ制限対策)ため、for ループを使った
親と子のレコードの作成→親子関係の設定→DML操作
のような処理を書くのが面倒です。
しかし、fflib_SObjectUnitOfWork クラスを使うことで、シンプルで理解しやすいコードを書くことができます。
通常の書き方
親子関係のレコードを同時に作成する場合、通常は以下のような書き方になります。
- 親レコードの作成
- 親レコードの挿入(このタイミングでIDが設定される)
- 子レコードの主従(参照)関係に、親レコード.ID の値を設定する
- 子レコードの挿入
コードで書くとこんな感じです。
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();
コメント