保存処理で親オブジェクトと子オブジェクトを一緒に登録する際、親オブジェクト登録後の子オブジェクト登録に失敗した場合は、ロールバックで親オブジェクト登録を無かったことにできます。
このロールバック処理とUPSERT処理を組み合わせて処理する場合は、注意することがあります。
例えば次のように取引先をUPSERTで登録後、商談の登録前にエラー判定で処理を中断してロールバックする処理を行います。
public void doSave() { System.debug('◆◆◆◆doSave:START'); Savepoint sp = Database.setSavepoint(); upsert this.objAccount; this.objOpportunity = getOpportunity(this.objAccount,opportunityName); if (String.isEmpty(this.objOpportunity.Name) == true) { ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.Error, 'Not Opportunity Name!!')); Database.rollback(sp); return; } upsert this.objOpportunity; ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, 'Save!!')); System.debug('◆◆◆◆doSave:END'); }
一度ロールバックで取引先の登録をなかったことにした後に、再度取引先と商談の登録を実行すると次のようなエラーが発生します。
これは登録用の変数に最初のUPSERT時のIDがセットされたままになっているため発生しました。
ロールバックの処理ではDML処理は元に戻りますが、変数にセットしたIDは元に戻らないことが原因です。
※変数がIDを保持したままなのでUPSERT処理は更新として扱われますが、そのIDを持つデータが存在しないためエラーとなります。
これの対応方法をちょっと考えてみました。
このように更新用の変数に値をコピーします。
Account upsertAccount = this.objAccount.clone(true, false, true, true); upsert upsertAccount;
UPSERT用の変数は別の変数として用意することで、繰り返し処理を実行してもIDをクリアすることができます。
参考サイト
Database Methods
GitHub Link
Apex_Rollback