参照されたレコードをトリガーで削除しようとしてハマった

2020/04/05Salesforce

前提

カスタムオブジェクトA(以下、A)とAを参照するカスタムオブジェクトB(以下、B)の関係性。Aを削除するとBも併せて削除したいと思い、Triggerで削除することになった。

TriggerはInsertやUpdateは経験あるけど、Deleteって今までしたことなかったなぁ。でもDeleteやUnDeleteでも動くってことは知識としてあった。

事象

以下のようなTriggerを作って実行した。実際はHandlerに渡して~とかやってたけど、ここでは簡単のためにTrigger内で処理を書いている。

trigger myCustomObjectATrigger on CustomObjectA(after delete) {
  Map<CustomObjectA> mapA = (CustomObjectA)Trigger.new;
  List<CustomObjectB> listB = [SELECT Id FROM CustomObjectB WHERE RefCustomObjectA = :mapA.keySet()];
  if (listB.size() > 0) {
    delete listB;
  } 
}

これを実行するとカスタムオブジェクトBが同じタイミングで削除されることを期待していたけど削除されない。

なぜ削除されないのかわからず、開発者コンソールを立ち上げた状態でデバッグ仕込んだり、SOQLを適宜Refreshしながら悩んでた。

原因

SOQLでレコードの状態を見てみる。カスタムオブジェクトAは確実に消える。これは画面から削除したから当然として、問題はカスタムオブジェクトB。消えない。ただ、消えないだけじゃなくてカスタムオブジェクトAの参照項目(RefCustomObjectA)だけnullになる。

え、なんで消えるの?

なんの処理もしてないけど。。。

RefCustomObjectAがnullだから削除できないのはわかったけど、なぜnullに?

でも、ここは消えるものと考えて、nullだから目的のレコードが取得できずにカスタムオブジェクトBが消えなかったことがわかった。

対策

Triggerのタイミングがafter deleteで、消えた前提で動いているようだったので、before deleteで動くように修正してあげることで動いた!

trigger myCustomObjectATrigger on CustomObjectA(before delete) {
  Map<CustomObjectA> mapA = (CustomObjectA)Trigger.new;
  List<CustomObjectB> listB = [SELECT Id FROM CustomObjectB WHERE RefCustomObjectA = :mapA.keySet()];
  if (listB.size() > 0) {
    delete listB;
  } 
}