Apexレコード更新＆選択の一般化

### 問題
Salesforceの標準設定で開発が進めるなかに、カスタマイズ化しないといけない場面がよくあります。
案として、Flowで基本的にできますが、操作性便利性がなかなかできないところがあります。スクリーンのボタンが三つ固定されているので、他の動作へのリックできない。別の画面へ移動させる場合、特に複数確認メッセージがありLwc実装になります。Db操作はできる限り、LightningDataService（LDS）を使って、裏のApexの開発がいらなく、余計のテストクラスもいらないです。でもLDSは一レコードだけの操作になります。複数レコードの作成する場合、Transactionができないです。LDSの複数レコード更新＆作成がTransactionできないので、Apexの実装になります。
### 案
複数レコードの用意はLWCのJavascriptで作成し、うらのApexが汎用的に作成する

### 参照資料
・LwcからApexのコール
　https://note.com/koji_matae/n/n2344bde286bc
・ApexとLwc間にJsonデータ交換
https://salesforce.stackexchange.com/questions/330273/deserialize-a-json-to-a-listsobject
・Confirmタイログ　
https://www.forcetrails.com/2022/06/create-confirm-dialogs-using-LightningConfirm-lwc.html

### Apex実装
#### InsertRecords
```
public with sharing class CommonDmlUtil {
    @AuraEnabled(cacheable=false)
    public static void commonInsertRecords(String strJSONData, String strType, Boolean boolIsList) {
        List<SObject> lstObjects = new List<SObject>();
        if (boolIsList) {
            lstObjects = (List<SObject>) JSON.deserialize(strJSONData, Type.forName(strType));
        } else {
            SObject obj = (SObject) JSON.deserialize(strJSONData, Type.forName(strType));
            lstObjects.add(obj);
        }
        System.debug('lstObject: '+lstObjects);

        insert lstObjects;
       
    }
}
```
・説明
引数１、JsonStringです。
　リストの場合例：
　　　'[{name:xxx1,contact__c:yyy1},{name:xxx2,contact__c:yyy2},...]'
  1Objectの場合
　　　'{name:xxx1,contact__c:yyy1}'
引数２　引数１のオブジェクトタイプ
　　リストの場合の例：　'List<Contact>'
    1 Objectの例；　'Contact'
引数３　引数１のリストの場合、True、一オブジェクトの場合Flase

#### SelectRecords
```
    /**
     * @name commonSelectRecords
     * @parameter String strSql 
     *   sample: 'select id, name from Contact'
     * @return List<SObject>
     */
    @AuraEnabled(cacheable=true)
    public static List<SObject> commonSelectRecords(String strSql) {

        return Database.query(strSql);
       
    }
```
### ApexにCountの使用例
```
List<AggregateResult> arr =
    CommonDmlUtil.commonSelectRecords('Select count(id) CNT from account');
System.debug(arr.get(0).get('CNT'));
```



### LWC側の例
　Account画面のボタンを押されると、関連二つContactを作成される
　確認メッセージとエラー情報を出す
Js
```
import { LightningElement, api, wire } from "lwc";
import LightningConfirm from "lightning/confirm";
import { NavigationMixin } from 'lightning/navigation';
import { getRecord,getFieldValue,createRecord } from 'lightning/uiRecordApi';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import commonInsertRecords from '@salesforce/apex/CommonDmlUtil.commonInsertRecords';

const fields = [
    'Account.Id',
    'Account.Type'
    ];

export default class CreateContactsOnBtn extends NavigationMixin( LightningElement ) {
    //bind recordId
    _recordId;

    result;  //list of db result

    @api set recordId(value) {
        this._recordId = value;
    }

    get recordId() {
        return this._recordId;
    }

    @wire(getRecord, { recordId: '$recordId', fields })
    account;

    get type() {
        return getFieldValue(this.account.data, 'Account.Type');
    } 
 
    @api async invoke() {
        console.log("Hi,test _recordId.12 -->" + this._recordId + ' <--');
  
        var countNum = 0;
        var contactList = [];
        for (var i=0; i<2; i++){

                var contact = {};
                contact['LastName'] = this.type + ' ' +i;
                contact['AccountId'] = this._recordId;

                contactList[countNum] = contact;
    
                countNum += 1;
            
        }

        //count == 0
        if( countNum == 0 ){
            console.log("Hi,test fields3 -->" + countNum + ' <--');

            let event = new ShowToastEvent({
                title: 'チェック',
                message: 'レコード作成対象は0件です。',
                variant: 'warning',
                mode: 'dismissable'
            });

            this.dispatchEvent(event);

            return;
                
        }
        //count >0
        if( countNum >0 ){
            const result = await LightningConfirm.open({
                message: 'キャンセルレコードを '+ countNum +'件 作成しますか？',
                variant: "default", // headerless
                label: ""
            });

            if (!result) {
                return;
            }        
        }

        //insert into db
        var param1 = JSON.stringify(contactList);
        console.log('JsonStr:' + param1);

        //exec
        commonInsertRecords({strJSONData: param1,strType:'List<Contact>',boolIsList: true })
        .then(result => {
            this.result = result;
            this.dispatchEvent( new ShowToastEvent({
                title: '処理結果',
                message: 'レコードの作成が完了しました。',
                variant: 'success',
                mode: 'dismissable'
            }));
        })
        .catch(error => {
            /*eslint no-console: "off"*/
            console.log(error);
            this.result = error;
            this.dispatchEvent( new ShowToastEvent({
                title: '処理結果',
                message: 'レコードの作成に失敗しました。\n' + error.body.message,
                variant: 'error',
                mode: 'dismissable'
            }));
        })

    }

}
```

html
```
<template>
</template>
```

xml
```
<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle
    xmlns="http://soap.sforce.com/2006/04/metadata"
    fqn="createContactsOnBtn">
    <apiVersion>55.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordAction</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
    <targetConfigs>
       <targetConfig targets="lightning__RecordAction">
         <actionType>Action</actionType>
       </targetConfig>
    </targetConfigs>
</LightningComponentBundle>
```
### 配置
ボタン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/801991/689de73e-d7f6-e78c-997d-1a1040a3c0c2.png)

ページレイアウト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/801991/acbffb3f-42be-8d6e-fe87-dc3c1f188673.png)

結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/801991/44dafe06-393d-e4a6-6c63-92845bab9b71.png)