進行状況の追跡を始めよう
Trailhead のホーム
Trailhead のホーム

Apex を使用したデータの操作

学習の目的

この単元を完了すると、次のことができるようになります。

  • どのような場合に Apex を使用して Salesforce データを操作する必要があるかを認識する。
  • 2 つの異なる方法で Apex をコールする。
  • Apex と lightning-datatable を使用してレコードのリストを操作する。

Lightning Web コンポーネントでの Apex

Lightning データサービスのメリットと使用方法を学習しましたが、lightning-record-*-form コンポーネントも LDS ワイヤアダプタや関数も適さない特定の使用事例がある場合もあります。たとえば、レコードデータが 1 件のトランザクションをカスタマイズする場合や、1 つのトランザクションで複数レコードの操作を実行する場合、Apex が最適です。

Lightning Web コンポーネントでの Apex の使用

Lightning Web コンポーネントで使用される Apex メソッドは staticpublicglobal のいずれかで、メソッド定義の直前に @AuraEnabled アノテーションが付加されている必要があります。@AuraEnabled アノテーションによって Apex メソッドを Lightning コンポーネント (Lightning Web コンポーネントと Aura コンポーネントの両方) で使用できるようになります。

フレームワークがデータをキャッシュできるようにすることで、サーバコールの繰り返しがなくなり、以降の参照操作の実行が速くなります。@AuraEnabled アノテーションに cacheable = true と設定すると、メソッドがキャッシュ可能とマークされます。@AuraEnabled メソッドがキャッシュ可能の場合、データ操作言語 (DML) による操作は許可されません。次の例の行 2 では、getRelatedContacts メソッドがキャッシュ可能と指定されています。

AccountController.cls

public with sharing class AccountController {
    @AuraEnabled(cacheable=true)
    public static List<Contact> getRelatedContacts(Id accountId) {
        return [
            SELECT Name, Title, Email, Phone
            FROM Contact
            WHERE AccountId = :accountId
            WITH SECURITY_ENFORCED
       ];
    }
}

メソッドがキャッシュ可能の場合、キャッシュが更新されるまで新しく追加または変更されたレコードのバージョンが返されません。次のセクションでキャッシュを手動で更新する方法を説明します。

LWC からの Apex メソッドコール

Lightning Web コンポーネントから Apex メソッドを操作するには、メソッドを結び付けるか、命令的にメソッドをコールするという 2 つの方法があります。両方のアプローチを考えてみましょう。

@wire を使用した Apex コール

Apex メソッドを結び付けるには、メソッドを cacheable にする必要があります。キャッシュ可能な Apex メソッドを結び付けるには、@wire デコレータを使用します (LDS ワイヤアダプタを使用する場合と同じ方法)。この方法で Apex をコールすると Lightning Web コンポーネントエンジンに制御が委任されてリアクティブサービスが作成されます。Apex メソッドに渡されるパラメータの値が変わるたびに、Apex メソッドはデコレートされたプロパティまたは関数に新しい値をプロビジョニングします。結び付けられたメソッドがキャッシュ可能である必要があるため、データは LDS キャッシュまたはサーバから取得される可能性があります。Apex メソッドによってキャッシュされたデータを更新するには、refreshApex 関数をコールします。

注意: Lightning データサービスは、Apex メソッドによってキャッシュされたデータを認識しません。LDS 関数がレコードを更新すると、その更新は Apex メソッドによってキャッシュされたデータに影響を与えません。

次の例では @wire を使用して Apex をコールしています。このコードは取引先の関連取引先責任者を取得します。

wireApexProperty.js

import { LightningElement, api, wire } from 'lwc';
import getRelatedContacts from '@salesforce/apex/AccountController.getRelatedContacts';
export default class WireApexProperty extends LightningElement {
    @api recordId;
    @wire(getRelatedContacts, { accountId: '$recordId' })
    contacts;
}

コードのポイント:

  • 行 2: getRelatedContacts 関数を AccountController Apex クラスからインポートします。これは対応する Apex メソッドを参照します。
  • 行 4: @api recordId プロパティを定義して、FlexiPage が現在のレコードの ID をコンポーネントに渡せるようにします。
  • 行 5: @wire デコレータが 2 つのパラメータ (コールする Apex メソッド (getRelatedContacts) とアダプタに必要なパラメータ (accountId)) を受け取ります。$recordId をリアクティブ変数 (先頭が $) として渡します。
  • 行 6: 結果を contacts プロパティに保存します。
  • 行 5 ~ 6: 最初に Apex メソッドがデータを contacts プロパティにプロビジョニングし、そのデータを LDS キャッシュに保存します。$recordId はリアクティブであるため、その値が変更されるたびに Apex メソッドは新しいデータをキャッシュまたはサーバからプロビジョニングします。

命令的な Apex コール

@wire を使用して Apex をコールする代わりに、命令的に Apex をコールすることもできます。参照操作の呼び出しを制御する必要がある場合とレコードを変更する場合は、命令的に Apex をコールします。Apex を命令的にコールするには、Lightning Web コンポーネントエンジンに制御を委任する代わりに、コンポーネントの JavaScript ファイルから 1 回 Apex を呼び出します。JavaScript promise が返されます (LDS 関数を命令的にコールする場合と同様)。

キャッシュ可能な Apex メソッドとキャッシュ不能な Apex メソッドの両方を命令的にコールすることができます。キャッシュ可能なメソッドのキャッシュを更新するには、メソッドを再度コールします。

callApexImperative.js の例では、ユーザが .html ファイル内の lightning-button (ここには含まれていない) をクリックすると、handleButtonClick が命令的に getRelatedContacts Apex メソッドをコールします。

callApexImperative.js

import { LightningElement, api, wire } from 'lwc';
import getRelatedContacts from '@salesforce/apex/AccountController.getRelatedContacts';
export default class CallApexImperative extends LightningElement {
    @api recordId;
    handleButtonClick() {
        getRelatedContacts({ //imperative Apex call
            accountId: '$recordId'
        })
            .then(contacts => {
                //code to execute if related contacts are returned successfully
            })
            .catch(error => {
                //code to execute if related contacts are not returned successfully
            });
    }
}

コードのポイント:

  • 行 2: getRelatedContacts 関数を AccountController クラスからインポートします。
  • 行 4: public の recordId プロパティを定義して、このコンポーネントで関連取引先責任者が表示される取引先の ID を FlexiPage が渡せるようにします。
  • 行 6 ~ 7: handleButtonClick メソッドがフレームワークによって呼び出されると、getRelatedContacts Apex メソッドを命令的に呼び出し、メソッドが適切な取引先の関連取引先責任者を取得するのに必要な accountId を渡します。
  • 行 9 ~14: 行 6 の命令的な Apex コールが promise を返します。Apex メソッドコールが成功した場合、promise が満たされ、then メソッドが実行されます。それ以外の場合、promise は却下され、catch メソッドが実行されます。

Lightning Web サービスでレコードのリストを操作するのに適しているのは、lightning-datatable 基本コンポーネントを使用する方法です。lightning-datatable を使用して、無限スクロール、インライン編集、ヘッダーおよび行レベルのアクション、サイズ変更などの機能を持つデータのテーブルを作成します。UI コンポーネントにはデータが入力されている必要があります。そのデータを生成するには、このモジュールですでに説明した方法のいずれかで Apex をコールするのが最も一般的な方法です。

レコードをテーブルにリストする Lightning Web コンポーネントのリリース

lightning-datatable に既存の取引先のリストを表示する例を操作しましょう。Apex と @wire を使用してレコードを取得します。

  1. AccountController という名前の Apex クラスを作成します。
    1. エクスプローラペインで、classes フォルダを右クリックして [SFDX: Create Apex Class (SFDX: Apex クラスを作成)] を選択します。
    2. クラス名として「AccountController」と入力し、Enter キーを押します。
    3. もう一度 Enter キーを押して、デフォルトのディレクトリを受け入れます。
  2. AccountController クラスの内容を次のコードで置き換えます。
    public with sharing class AccountController {
        @AuraEnabled(cacheable=true)
        public static List<Account> getAccounts() {
            return [
                SELECT Name, AnnualRevenue, Industry
                FROM Account
                WITH SECURITY_ENFORCED
                ORDER BY Name
            ];
        }
    }

    コードのポイント:

    • 行 2: メソッドに @AuraEnabled(cacheable=true) アノテーションを付加して、結果がキャッシュされるようにします。
    • 行 3: Apex で getAccounts メソッドを定義して、参照操作を実行して既存の取引先を取得します。
  3. accountList という名前の Lightning Web コンポーネントを作成します。
  4. accountList.js ファイルの内容を次のコードで置き換えます。
    import { LightningElement, wire } from 'lwc';
    import NAME_FIELD from '@salesforce/schema/Account.Name';
    import REVENUE_FIELD from '@salesforce/schema/Account.AnnualRevenue';
    import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry';
    import getAccounts from '@salesforce/apex/AccountController.getAccounts';
    const COLUMNS = [
        { label: 'Account Name', fieldName: NAME_FIELD.fieldApiName, type: 'text' },
        { label: 'Annual Revenue', fieldName: REVENUE_FIELD.fieldApiName, type: 'currency' },
        { label: 'Industry', fieldName: INDUSTRY_FIELD.fieldApiName, type: 'text' }
    ];
    export default class AccountList extends LightningElement {
        columns = COLUMNS;
        @wire(getAccounts)
        accounts;
    }


    コードのポイント:

    • 行 2 ~ 4: 以前の例と同様に項目参照をインポートします。
    • 行 5: getAccounts 関数を AccountController クラスからインポートします。
    • 行 13: @wiregetAccounts 関数に使用してデータを取得します。
    • 行 14: 結果を accounts プロパティに保存します。操作が成功すると、レコードは accounts.data でアクセス可能になります。失敗するとエラーが account.error に表示されます。
  5. accountList.html ファイルの内容を次のコードで置き換えます。
    <template>
        <lightning-card>
            <template if:true={accounts.data}>
                <lightning-datatable
                    key-field="Id"
                    data={accounts.data}
                    columns={columns}
                >
               </lightning-datatable>
            </template>
        </lightning-card>
    </template>

    コードのポイント:

    • 行 4 ~ 9: lightning-datatable 基本コンポーネントを定義して、JavaScript ファイルに入力されている accounts.datacolumns を使用します。
  6. AccountController クラスを保存します。
  7. accountList.js-meta.xml の内容を次のコードで置き換えてコンポーネントをアプリケーションページで使用できるようにします。
    <?xml version="1.0" encoding="UTF-8"?>
    <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
        <apiVersion>48.0</apiVersion>
        <isExposed>true</isExposed>
        <targets>
            <target>lightning__AppPage</target>
        </targets>
    </LightningComponentBundle>
  8. 3 つのコンポーネントファイルをすべて保存します。
  9. force-app/main/default フォルダを Trailhead Playground にリリースします。
  10. Trailhead Playground で、Lightning アプリケーションビルダーに移動し、[Working with Data (データの操作)] ページを開きます。
  11. accountList コンポーネントをページのメインの範囲にドラッグします。
  12. ページを保存します。
  13. [Working with Data (データの操作)] ページに戻って新しいコンポーネントを表示します。
メモ

メモ

lightning-datatable コンポーネントを使用するときには、次の点に留意してください。

  • 一部のデータ型は現在 lightning-datatable コンポーネントでサポートされていません。ただし、カスタムデータ型は使用できます。詳細は、ドキュメントで「Create Custom Data Types」(カスタムデータ型の作成) までスクロールしてください。
  • lightning-datatable コンポーネントは現在モバイルでは動作しません。モバイルをサポートする必要がある場合は、代わりにカスタムテーブルを作成します。

Lightning Web コンポーネントで Salesforce データを操作するいくつかの方法を理解できました。次は、サーバエラーが発生したときの処理方法を学習します。

リソース