Salesforce LWCでのデータベースへのアクセス方法

# これは何？
この記事は「[24日後に立派なSalesforceエンジニアになるWEBエンジニア Advent Calendar 2022](https://qiita.com/advent-calendar/2022/kakakaori)」の9日目の記事です。１6日後に立派なSalesforceエンジニアになるために今日はLightning Web Component (LWC)からデータベースへのアクセスについて見ていきたいと思います。

# データの取得

## パターン１. lightning-record-formを使う
これが一番簡単な方法。レコードIDとオブジェクト名を指定して標準のレイアウトでレコードを表示する。modeにより編集などの指定も可能。以下のコードの場合は、レコードIDやオブジェクト名は配置したレコードページから取得してきており、画像はAccountページに配置したサンプルになっている。

```javascript:test.js
import { LightningElement, api } from 'lwc';

export default class Test extends LightningElement {
    @api recordId;
    @api objectApiName;
    fields = ['AccountId', 'Name', 'Phone', 'PersonEmail'];
}
```
```html:test.html
<template> 
    <lightning-record-form
        record-id={recordId} object-api-name={objectApiName} fields={fields} mode="view">
    </lightning-record-form>
    <lightning-record-form
        record-id={recordId} object-api-name={objectApiName} fields={fields} mode="readonly">
    </lightning-record-form>
    <lightning-record-form
        record-id={recordId} object-api-name={objectApiName} fields={fields} mode="edit">
    </lightning-record-form>
</template> 
```
上から順に`mode`が`edit` `view` `read-only`　になっている。
![スクリーンショット 2022-12-04 21.45.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/aa6c56b1-f190-fc5e-8c50-d4fe37ae6cdd.png)

## パターン２. lightning-record-view-formを使う
レイアウトをカスタマイズしたい場合はこちら。先ほどとほとんど一緒だが表示の仕方を変更することができる。
ちなみにLWCでは[Lightning Design System](https://www.lightningdesignsystem.com/)と呼ばれるデザインシステムが用意されているのでレイアウトをカスタマイズするときはそれを参考にすると良い。ある程度パターン化されたものが[Base Component](https://developer.salesforce.com/docs/component-library/overview/components)としても用意されているのでそちらも上手く活用するといい感じの画面が簡単に作れそう。

```javascript:test.js
import { LightningElement, api } from 'lwc';

export default class Test extends LightningElement {
    @api recordId;
}
```
```html:test.html
<template>
    <lightning-record-view-form
                record-id={recordId}
                object-api-name="Account">
        <div class="slds-grid">
            <div class="slds-col slds-size_1-of-2">
                <lightning-output-field field-name="Name"></lightning-output-field>
                <lightning-output-field field-name="Phone"></lightning-output-field>
            </div>
            <div class="slds-col slds-size_1-of-2">
                <lightning-output-field field-name="Industry"></lightning-output-field>
                <lightning-output-field field-name="AnnualRevenue"></lightning-output-field>
            </div>
        </div>
    </lightning-record-view-form>
</template>
```
デフォルトは１カラムだったのが２カラムにカスタマイズされた。
![スクリーンショット 2022-12-04 21.54.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/108c6652-19b7-adf4-49ab-ad063a11cb9a.png)

## パターン3. getRecordを使う
`lightning-record-form`も`lightning-record-view-form`もフォームの見た目しか表現できないので、フォームじゃないレイアウトを使ってさらに柔軟な見た目にしたいときはこれを使う。

```javascript:test.js
import { LightningElement, api, wire } from 'lwc';
import { getRecord } from 'lightning/uiRecordApi';
const FIELDS = ['Account.Name', 'Account.Phone'];

export default class Test extends LightningElement {
    @api recordId;

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

    get name() {
        return this.account.data.fields.Name.value;
    }
}
```
取ってきた項目を表示するときは`account.data.fields.Name.value`のようにして呼び出すが、html内でそれを記述してもいいしjs側にgetterを用意しておいてそれを呼び出しても良い。
accountの情報を取得する前にレンダリングされてデータがなくてエラーで落ちてしまうのを防ぐために`<template if:true={account.data}>`を入れてデータの取得後のみ表示するようにしている。
```html:test.html
<template>
    <lightning-card icon-name="standard:account">
        <template if:true={account.data}>
            <div class="slds-p-horizontal_small">
                <p>{name}</p>
                <p><lightning-formatted-phone value={account.data.fields.Phone.value}></lightning-formatted-phone></p>
            </div>
        </template>
    </lightning-card>
</template>
```

## パターン4. Apexクラスを使う
ここまでのやり方は全てレコードIdを指定することでデータを取得してきたが、レコードId以外を指定してデータを取得するときや、複数テーブルをjoinした結果を取得したいときなどはこのやり方を使う。ApexクラスでSOQLを書いてデータを取得し、javascriptに返してやり表示する感じ。

まずApexクラスを作成する。作成はここから。
![スクリーンショット 2022-12-04 22.20.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/50f44bd4-a172-2f22-61b4-3d9b9c0e3ac0.png)
今回はサンプルとして`Name`を指定してレコードを一件取得してきて表示する。
```apex:testController.cls
public with sharing class testController {
  @AuraEnabled(cacheable=true) // wireサービスから呼び出すためにはこれが必要
  public static Account getAccountByName(String name) {
    List<Account> account = [
      SELECT
        Id,
        Phone,
        Name
      FROM Account
      WHERE Name = :name
      LIMIT 1
    ];

    return account[0];
  }
}
```
上記で作ったApexクラスをjsにインポートする。

```javascript:test.js
import { LightningElement, api, wire } from 'lwc';
// 先ほどのApexクラスをインポート
import getAccountByName from '@salesforce/apex/testController.getAccountByName';

export default class Test extends LightningElement {
    @api recordId;

    // ここでApexクラスのメソッドを呼び出して、戻り値をaccountDataに接続
    @wire(getAccountByName, { name: 'test' })
    accountData;

    get name() {
        return this.accountData.data.Name;
    }

    // もしくは @wire を使わずに以下のように直接Apexメソッドを呼び出すこともできる
    connectedCallback() {
        getAccountByName({
            name : 'test'
        })
        .then( data => { // 正常終了時の処理
        } )
        .catch((error) => { // 異常終了時の処理
        });
    }
}

```
getRecordの時は取ってきた項目を表示するのに`account.data.fields.Name.value`という書き方をしていたが、今回の場合は`accountData.data.Name`という形で呼び出すことになるので注意。
```html:test.html
<template>
    <lightning-card icon-name="standard:account">
        <template if:true={accountData.data}>
            <div class="slds-p-horizontal_small">
                <p>{name}</p>
                <p><lightning-formatted-phone value={accountData.data.Phone}></lightning-formatted-phone></p>
            </div>
        </template>
    </lightning-card>
</template>
```
表示についてはパターン３と全く同じなので割愛。

# 最後に
今回はLWCでレコードを取得して表示する方法についていくつかあるのでそれをまとめてみました。どのパターンも結構簡単に表示ができるなという印象。また途中に書いた[Lightning Design System](https://www.lightningdesignsystem.com/)や[Base Component](https://developer.salesforce.com/docs/component-library/overview/components)も提供されているので、標準ぽい画面を簡単に作れそうですね。
明日はLWCのデコレータについて見ていきたいと思います。