function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
吉田 丈治吉田 丈治 

データを削除した時に関連するレコードの特定のフラグを削除したい Trigger.oldとTrigger.new

こちらを参照してトリガとハンドラを作っています

商談オブジェクト(Opportunity)の中にカスタム項目で親商談(parentOpp__c)という項目を作り、商談に親子関係を作っています。
親商談1に対して子商談が複数付く事があります。

トリガで実現したいのは、
1:子商談の紐付けがされた時に親商談の親商談フラグ(parentOppFlag__c)をTRUEにするということと
2:子商談の親商談の紐付け(parentOpp__c)が削除された時、子商談自体が削除された時に、削除された parentOpp__cのIDを持っている商談をSELECTしてそのリストが1以上だった場合は親の商談のparentOppFlag__cはTRUEのまま。0だった場合にはparentOppFlag__cをFALSEにする
というものです。

1については、冒頭のリンク先を参照して以下のように実装しました。
2については、Trigger.oldを使ってデータを取得する必要がありどのように実装すべきかがわかっておりせん。
どなたかお知恵を拝借できないでしょうか。

1のコードは以下の通り

Trigger
trigger updateChildOppTrigger on Opportunity (after update , after delete , after insert) {
    
    updateChildOppTriggerHandler handler = new updateChildOppTriggerHandler();
    
    if (Trigger.isAfter) {
        if (Trigger.isInsert) {
            // 新規の場合:親商談がある商談を更新
            handler.updateOpportunityInsert(Trigger.new);
        }

    }
}


Handler
public with sharing class updateChildOppTriggerHandler {

    public updateChildOppTriggerHandler() {
        
    }

    public void updateOpportunityInsert(List<Opportunity> prmOpportunities) {
        
        // 最初に商談に紐付く親商談IDを取得
    	Set<Id> opportunityIds = new Set<Id>();
        for (Opportunity o : prmOpportunities) {
            if (String.isNotEmpty(o.parentOpp__c )) {
            	opportunityIds.add(o.parentOpp__c );
            }
        }

        // 取引先IDを条件に取引先を取得する
        List<Opportunity> opportunities = [SELECT Id,parentOpp__c  FROM Opportunity WHERE Id IN: opportunityIds];

        // 取引先に値をセットする
        for (Opportunity a : opportunities) {
        	a.parentOppFlag__c = True;
        }

        // 取引先を更新する
        update opportunities;
    }
}

 
Best Answer chosen by 吉田 丈治
Shun KosakaShun Kosaka
素直に実装してみました。ポイントと思われる点は下記です。
・ゴミ箱からのレコード復元時(after undelete)も考慮が必要かと思います。
・削除時はTrigger.newがnullになるため、Trigger.oldのうち親商談をもつレコードを抽出します。(レコード復元時は逆になります。)
・Trigger.newとTrigger.oldを比較することで、親商談が変化したレコードを抽出します。
・子レコードの件数は集計関数+AggregateResultでも取得できますが、コードが煩雑になるためサブクエリとsize()の組み合わせがよいかと思います。

以下、トリガです。
trigger updateChildOppTrigger on Opportunity (after update , after delete , after insert, after undelete) {
    
    updateChildOppTriggerHandler handler = new updateChildOppTriggerHandler();
    
    if (Trigger.isAfter) {
        if (Trigger.isInsert) {
            // 新規の場合:親商談がある商談を更新
            handler.updateOpportunityInsert(Trigger.new);
        }
        if (Trigger.isUpdate || Trigger.isDelete || Trigger.isUndelete){
            handler.updateOpportunity(Trigger.old, Trigger.new);
        }
    }
}
以下、ハンドラに追加したメソッドです。(簡便のためひとつのメソッドにまとめていますが、適宜リネーム&分割いただければ幸いです。また、Opportunities__rは、parentOpp__cの子リレーション名に置き換えてください。)
public void updateOpportunity(List<Opportunity> prmOldOpportunities, List<Opportunity> prmNewOpportunities){
        // フラグ更新対象の親商談IDを格納
        Set<Id> opportunityIds = new Set<Id>();
        if(prmOldOpportunities == null) { //undelete
            for(Opportunity o : prmNewOpportunities){
                if(String.isNotEmpty(o.parentOpp__c )){
                    opportunityIds.add(o.parentOpp__c);
                }
            }
        } 
        else if(prmNewOpportunities == null){ //delete
            for(Opportunity o : prmOldOpportunities){
                if(String.isNotEmpty(o.parentOpp__c )){
                    opportunityIds.add(o.parentOpp__c);
                }
            }
        } else { //update
            Map<Id, Opportunity> newOpportunitiesMap = new Map<Id, Opportunity>(prmNewOpportunities);
            for(Opportunity o : prmOldOpportunities){
                if(o.parentOpp__c != newOpportunitiesMap.get(o.Id).parentOpp__c){
                    if(o.parentOpp__c != null){
                        opportunityIds.add(o.parentOpp__c);
                    }
                    if(newOpportunitiesMap.get(o.Id).parentOpp__c != null){
                        opportunityIds.add(newOpportunitiesMap.get(o.Id).parentOpp__c); 
                    }                    
                }
            }
        }
        // 親商談ID毎に、子商談の件数をカウントする
        List<Opportunity> opportunities = [SELECT Id, (SELECT Id FROM Opportunities__r) FROM Opportunity WHERE Id IN : opportunityIds];
        for(Opportunity o : opportunities){
            if(o.Opportunities__r.size() > 0){
                o.parentOppFlag__c = True;
            } else {
                o.parentOppFlag__c = False;
            }    
        }
        // 商談を更新する
        update opportunities;
    }

 

All Answers

Shun KosakaShun Kosaka
素直に実装してみました。ポイントと思われる点は下記です。
・ゴミ箱からのレコード復元時(after undelete)も考慮が必要かと思います。
・削除時はTrigger.newがnullになるため、Trigger.oldのうち親商談をもつレコードを抽出します。(レコード復元時は逆になります。)
・Trigger.newとTrigger.oldを比較することで、親商談が変化したレコードを抽出します。
・子レコードの件数は集計関数+AggregateResultでも取得できますが、コードが煩雑になるためサブクエリとsize()の組み合わせがよいかと思います。

以下、トリガです。
trigger updateChildOppTrigger on Opportunity (after update , after delete , after insert, after undelete) {
    
    updateChildOppTriggerHandler handler = new updateChildOppTriggerHandler();
    
    if (Trigger.isAfter) {
        if (Trigger.isInsert) {
            // 新規の場合:親商談がある商談を更新
            handler.updateOpportunityInsert(Trigger.new);
        }
        if (Trigger.isUpdate || Trigger.isDelete || Trigger.isUndelete){
            handler.updateOpportunity(Trigger.old, Trigger.new);
        }
    }
}
以下、ハンドラに追加したメソッドです。(簡便のためひとつのメソッドにまとめていますが、適宜リネーム&分割いただければ幸いです。また、Opportunities__rは、parentOpp__cの子リレーション名に置き換えてください。)
public void updateOpportunity(List<Opportunity> prmOldOpportunities, List<Opportunity> prmNewOpportunities){
        // フラグ更新対象の親商談IDを格納
        Set<Id> opportunityIds = new Set<Id>();
        if(prmOldOpportunities == null) { //undelete
            for(Opportunity o : prmNewOpportunities){
                if(String.isNotEmpty(o.parentOpp__c )){
                    opportunityIds.add(o.parentOpp__c);
                }
            }
        } 
        else if(prmNewOpportunities == null){ //delete
            for(Opportunity o : prmOldOpportunities){
                if(String.isNotEmpty(o.parentOpp__c )){
                    opportunityIds.add(o.parentOpp__c);
                }
            }
        } else { //update
            Map<Id, Opportunity> newOpportunitiesMap = new Map<Id, Opportunity>(prmNewOpportunities);
            for(Opportunity o : prmOldOpportunities){
                if(o.parentOpp__c != newOpportunitiesMap.get(o.Id).parentOpp__c){
                    if(o.parentOpp__c != null){
                        opportunityIds.add(o.parentOpp__c);
                    }
                    if(newOpportunitiesMap.get(o.Id).parentOpp__c != null){
                        opportunityIds.add(newOpportunitiesMap.get(o.Id).parentOpp__c); 
                    }                    
                }
            }
        }
        // 親商談ID毎に、子商談の件数をカウントする
        List<Opportunity> opportunities = [SELECT Id, (SELECT Id FROM Opportunities__r) FROM Opportunity WHERE Id IN : opportunityIds];
        for(Opportunity o : opportunities){
            if(o.Opportunities__r.size() > 0){
                o.parentOppFlag__c = True;
            } else {
                o.parentOppFlag__c = False;
            }    
        }
        // 商談を更新する
        update opportunities;
    }

 
This was selected as the best answer
吉田 丈治吉田 丈治
Shun Kosakaさん

ありがとうございます。なるほど、undeleteの時を考慮する必要があるんですね。

そして
updateOpportunity(List<Opportunity> prmOldOpportunities, List<Opportunity> prmNewOpportunities)

こうやってnewとoldをいっぺんに取得すればよかったんですね…
的確なアドバイスありがとうございます!