tyoshikawa1106のブログ

- Force.com Developer Blog -

SFDC:ロールバックについて

保存処理で親オブジェクトと子オブジェクトを一緒に登録する際、親オブジェクト登録後の子オブジェクト登録に失敗した場合は、ロールバックで親オブジェクト登録を無かったことにできます。


このロールバック処理と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');
}


一度ロールバックで取引先の登録をなかったことにした後に、再度取引先と商談の登録を実行すると次のようなエラーが発生します。
f:id:tyoshikawa1106:20130320225937p:plain


これは登録用の変数に最初のUPSERT時のIDがセットされたままになっているため発生しました。
ロールバックの処理ではDML処理は元に戻りますが、変数にセットしたIDは元に戻らないことが原因です。
※変数がIDを保持したままなのでUPSERT処理は更新として扱われますが、そのIDを持つデータが存在しないためエラーとなります。


これの対応方法をちょっと考えてみました。
このように更新用の変数に値をコピーします。

Account upsertAccount = this.objAccount.clone(true, false, true, true);
upsert upsertAccount;


UPSERT用の変数は別の変数として用意することで、繰り返し処理を実行してもIDをクリアすることができます。

参考サイト

Database Methods

http://goo.gl/1UuJD