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 メソッドは static
、public
、global
のいずれかで、メソッド定義の直前に @AuraEnabled
アノテーションが付加されている必要があります。@AuraEnabled
アノテーションによって Apex メソッドを Lightning コンポーネント (Lightning Web コンポーネントと Aura コンポーネントの両方) で使用できるようになります。
フレームワークがデータをキャッシュできるようにすることで、サーバーコールの繰り返しがなくなり、以降の参照操作の実行が速くなります。@AuraEnabled
アノテーションに cacheable = true
と設定すると、メソッドがキャッシュ可能とマークされます。@AuraEnabled
メソッドがキャッシュ可能の場合、データ操作言語 (DML) による操作は許可されません。次の例の行 2 では、getContactsBornAfter
メソッドがキャッシュ可能と指定されています。
ContactController.cls
public with sharing class ContactController { @AuraEnabled(cacheable=true) public static List<Contact> getContactsBornAfter(Date birthDate) { return [ SELECT Name, Title, Email, Phone FROM Contact WHERE Birthdate > :birthDate 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 getContactsBornAfter from '@salesforce/apex/ContactController.getContactsBornAfter'; export default class WireApexProperty extends LightningElement { @api minBirthDate; @wire(getContactsBornAfter, { birthDate: '$minBirthDate' }) contacts; }
コードのポイント:
- 行 2:
getContactsBornAfter
関数をContactController
Apex クラスからインポートします。これは対応する Apex メソッドを参照します。 - 行 4:
@api minBirthDate
プロパティを定義します。このコンポーネントをコード内で使用したり、FlexiPage 属性を公開したりする場合は、日付を@api minBirthDate
プロパティに渡すことができます。 - 行 5:
@wire
デコレーターが 2 つのパラメーター (コールする Apex メソッド (getContactsBornAfter
) とアダプターに必要なパラメーター (birthDate
)) を受け取ります。$minBirthDate
をリアクティブ変数 (先頭が$
) として渡します。 - 行 6: 結果を
contacts
プロパティに保存します。 - 行 5 ~ 6: 最初に Apex メソッドがデータを
contacts
プロパティにプロビジョニングし、そのデータを LDS キャッシュに保存します。$minBirthDate
はリアクティブであるため、その値が変更されるたびに Apex メソッドが実行され、新しいデータがキャッシュまたはサーバーからプロビジョニングされます。
命令的な Apex コール
@wire
を使用して Apex をコールする代わりに、命令的に Apex をコールすることもできます。参照操作の呼び出しを制御する必要がある場合とレコードを変更する場合は、命令的に Apex をコールします。Apex を命令的にコールするには、インポートした関数をコンポーネントの JavaScript ファイルから呼び出します。この関数は JavaScript promise を返します (LDS 関数を命令的にコールする場合と同様)。
キャッシュ可能な Apex メソッドとキャッシュ不能な Apex メソッドの両方を命令的にコールすることができます。ただし、キャッシュ可能な Apex メソッドを命令的に更新することはできません。代わりに、@wire
を使用してメソッドをコールし、refreshApex
で更新します。
callApexImperative.js の例では、ユーザーが .html ファイル内の lightning-button
(ここには含まれていない) をクリックすると、handleButtonClick
が命令的に getContactsBornAfter
Apex メソッドをコールします。
callApexImperative.js
import { LightningElement, api, wire } from 'lwc'; import getContactsBornAfter from '@salesforce/apex/ContactController.getContactsBornAfter'; export default class CallApexImperative extends LightningElement { @api minBirthDate; handleButtonClick() { getContactsBornAfter({ //imperative Apex call birthDate: this.minBirthDate }) .then(contacts => { //code to execute if related contacts are returned successfully }) .catch(error => { //code to execute if related contacts are not returned successfully }); } }
コードのポイント:
- 行 2:
getContactsBornAfter
関数をContactController
クラスからインポートします。 - 行 4:
minBirthDate
公開プロパティを定義します。これで、このコンポーネントをコードで使用したり、FlexiPage 属性を公開したりする際に日付を渡すことができるようになります。 - 行 6 ~ 7:
handleButtonClick
メソッドがフレームワークによって呼び出されると、getContactsBornAfter
Apex メソッドを命令的に呼び出し、メソッドが指定された生年月日より後に生まれた取引先責任者を取得するのに必要なbirthDate
を渡します。 - 行 9 ~ 14: 行 6 の命令的な Apex コールが promise を返します。Apex メソッドコールが成功した場合、promise が満たされ、
then
メソッドが実行されます。それ以外の場合、promise は却下され、catch
メソッドが実行されます。
Lightning Web サービスでレコードのリストを操作するのに適しているのは、lightning-datatable
基本コンポーネントを使用する方法です。lightning-datatable
を使用して、無限スクロール、インライン編集、ヘッダーおよび行レベルのアクション、サイズ変更などの機能を持つデータのテーブルを作成します。UI コンポーネントにはデータが入力されている必要があります。そのデータを生成するには、このモジュールですでに説明した方法のいずれかで Apex をコールするのが最も一般的な方法です。
レコードをテーブルにリストする Lightning Web コンポーネントのリリース
lightning-datatable
に既存の取引先のリストを表示する例を操作しましょう。Apex と @wire
を使用してレコードを取得します。
AccountController
という名前の Apex クラスを作成します。
- エクスプローラーペインで、classes フォルダーを右クリックして [SFDX: Create Apex Class (SFDX: Apex クラスを作成)] を選択します。
- クラス名として
「AccountController」
と入力し、Enter キーを押します。 - もう一度 Enter キーを押して、デフォルトのディレクトリを受け入れます。
- 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
メソッドを定義して、参照操作を実行して既存の取引先を取得します。
accountList
という名前の Lightning Web コンポーネントを作成します。- 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:
@wire
をgetAccounts
関数に使用してデータを取得します。 - 行 14: 結果を
accounts
プロパティに保存します。操作が成功すると、レコードはaccounts.data
でアクセス可能になります。失敗するとエラーがaccount.error
に表示されます。
- 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.data
とcolumns
を使用します。
- AccountController クラスを保存します。
- 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>
- 3 つのコンポーネントファイルをすべて保存します。
- force-app/main/default フォルダーを Trailhead Playground にリリースします。
- Trailhead Playground で、Lightning アプリケーションビルダーに移動し、[Working with Data (データの操作)] ページを開きます。
- accountList コンポーネントをページのメインの範囲にドラッグします。
- ページを保存します。
- [Working with Data (データの操作)] ページに戻って新しいコンポーネントを表示します。
Lightning Web コンポーネントで Salesforce データを操作するいくつかの方法を理解できました。次は、サーバーエラーが発生したときの処理方法を学習します。
リソース