ChatGPTでApexトリガーを書いてもらう

# はじめに

ChatGPTにSalesforceのコード(Apex Trigger)もかけるのか検証してみます。
検索モデル「GPT-4」はどの程度の精度で実装してくれるのでしょうか。

# 結論

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214653/cbbff631-1ac5-8c48-de6a-e614b8004c33.png)

# 質問内容

```
以下の内容で、SalesforceのApexトリガーを書いてください。
・Accountが更新されると親取引先のNameを〇〇に設定する
```

# 回答

```apex
trigger UpdateParentAccount on Account (after update) {
    // 変更されたアカウントのIDを取得
    Set<Id> updatedAccountIds = new Set<Id>();
    for (Account acc : Trigger.new) {
        if (acc.ParentId != null && acc.Parent.Name != '〇〇' && acc.Parent.Name != '△△') {
            updatedAccountIds.add(acc.Id);
        }
    }
    if (updatedAccountIds.isEmpty()) {
        return;
    }
    
    // 変更されたアカウントの親アカウントを取得
    List<Account> parentAccounts = [SELECT Id, Name FROM Account WHERE Id IN :updatedAccountIds AND ParentId != null];
    
    // 親アカウントのNameを変更
    for (Account parentAccount : parentAccounts) {
        parentAccount.Name = '〇〇';
    }
    update parentAccounts;
}
```

それっぽい形で書けていますが思ったよりイけてないコードです。
気になった点は以下

- acc.Parent.Name != '△△' の場合に処理対象から外す条件を付けている。気をきかせてくれたのでしょうか。
- updatedAccountIds に acc.Id を渡しているため無限ループしてしまう。acc.ParentId を渡すべきです。完全にバグです。
- 親取引先レコードを取りに行くSOQLで ParentId != null と書いています。これも特に意味のない処理になってますね。

# 指摘～修正

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214653/b86437b4-6f34-8891-369b-a777c1d4ee44.png)


```
以下の点を修正してください。
・acc.Parent.Name != '△△' の条件は不要です。
・updatedAccountIds に[[acc.Id](http://acc.id/)] を渡しているため無限ループします。ParentIdを渡してください。
・親取引先レコードを取りに行くSOQLについて、[ParentId != null] と書いているが必要ですか？
```

```apex
trigger UpdateParentAccount on Account (after update) {
    // 変更されたアカウントの親アカウントIDを取得
    Set<Id> updatedParentAccountIds = new Set<Id>();
    for (Account acc : Trigger.new) {
        if (acc.ParentId != null) {
            updatedParentAccountIds.add(acc.ParentId);
        }
    }
    if (updatedParentAccountIds.isEmpty()) {
        return;
    }
    
    // 変更されたアカウントの親アカウントを取得
    List<Account> parentAccounts = [SELECT Id, Name FROM Account WHERE Id IN :updatedParentAccountIds];
    
    // 親アカウントのNameを変更
    for (Account parentAccount : parentAccounts) {
        parentAccount.Name = '〇〇';
    }
    update parentAccounts;
}

```

acc.Parent.Name != '〇〇' のコードも一緒に消えてしまいましたが、動作自体に問題はなさそうです。
一度の指摘でちゃんと修正できました。

# 何度か同じ質問をしてみた

別のプロンプトを起動し、全く同じ質問をして結果を確認してみました。

## 質問2回目(動くコードを生成してくれた)

```apex
trigger UpdateParentAccountName on Account (before update) {
    List<Id> parentAccountIds = new List<Id>();
    
    for (Account updatedAccount : Trigger.new) {
        if (updatedAccount.ParentId != null) {
            parentAccountIds.add(updatedAccount.ParentId);
        }
    }
    
    if (!parentAccountIds.isEmpty()) {
        List<Account> parentAccountsToUpdate = [SELECT Id, Name FROM Account WHERE Id IN :parentAccountIds];
        
        for (Account parentAccount : parentAccountsToUpdate) {
            parentAccount.Name = '〇〇';
        }
        
        update parentAccountsToUpdate;
    }
}
```

## 質問3回目(動くコードを生成してくれた)

```apex
trigger UpdateParentAccountName on Account (after update) {
    List<Id> parentAccountIds = new List<Id>();

    for (Account updatedAccount : Trigger.new) {
        Account oldAccount = Trigger.oldMap.get(updatedAccount.Id);

        // 親取引先が変更された場合にのみ実行
        if (updatedAccount.ParentId != oldAccount.ParentId) {
            parentAccountIds.add(updatedAccount.ParentId);
        }
    }

    if (!parentAccountIds.isEmpty()) {
        List<Account> parentAccountsToUpdate = [SELECT Id, Name FROM Account WHERE Id IN :parentAccountIds];

        for (Account parentAccount : parentAccountsToUpdate) {
            parentAccount.Name = '〇〇';
        }

        update parentAccountsToUpdate;
    }
}
```

- SOQL書いている行が横に長いなと感じますが、特に問題ないと思います
- 最初の回答にあった [acc.Parent.Name != '〇〇'] も無くなってます

## 質問4回目(動かないコードが生成された)

```apex
trigger UpdateParentAccountName on Account (after update) {
    // Account Idsを格納するためのSetを作成
    Set<Id> accountIds = new Set<Id>();

    // 更新されたアカウントのIdを取得
    for (Account acc : Trigger.new) {
        accountIds.add(acc.Id);
    }

    // 親取引先 (Parent Account) を取得
    List<Account> parentAccounts = [
        SELECT Id, Name, ParentId
        FROM Account
        WHERE Id IN :accountIds
        AND ParentId != null
    ];

    // 親取引先のNameを〇〇に設定する
    for (Account parentAcc : parentAccounts) {
        parentAcc.Name = '〇〇';
    }

    // 親取引先 (Parent Account) を更新
    update parentAccounts;
}
```

- accountIdsに溜め込むIDをParentIdではなくIdを使ってしまっている

# まとめ

Salesforceの特性を理解してコードを1発で書き切るにはまだ十分ではないようです。
ただし改善点を伝えるときちんと対応してくれるので、現時点でもプログラマとして非常に優秀だと思わせてくれる結果になりました。