Salesforce開発の基礎編5
Apex の基礎とデータベース
Apex の使用開始
まぁJava書いてたら特に問題なくやれる。言語仕様は体感 Java1.42 位の印象(1.4 よりはマシ?だが5の様なGenericsなどは存在しない)。
ローカルコンパイルできず、Salesforce 組織上でしかコンパイル/実行できない。
Apex の特徴的な機能として
- クラウド開発 (Apex はクラウドで保管、コンパイル、および実行されるため)
- トリガ (データベースシステムのトリガと類似)
- 直接データベースコールが可能なデータベースステートメントと、データのクエリと検索を行うためのクエリ言語
- トランザクションとロールバック
- global アクセス修飾子 (public 修飾子よりも権限が高く、名前空間とアプリケーションの全体でアクセスが可能)
- カスタムコードのバージョン管理
サンプルのコードは非常にうれしい作りではあるのでここでも転記。
Java だとメールサーバに接続して…なんて色々やるけど、そういった内容はすべて Salesforce にビルトイン。
こういう所は楽っちゃ楽
public class EmailManager { public void sendMail(String address, String subject, String body) { Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage(); String[] toAddresses = new String[] {address}; mail.setToAddresses(toAddresses); mail.setSubject(subject); mail.setPlainTextBody(body); Messaging.SendEmailResult[] results = Messaging.sendEmail( new Messaging.SingleEmailMessage[] { mail }); inspectResults(results); } private static Boolean inspectResults(Messaging.SendEmailResult[] results) { Boolean sendResult = true; for (Messaging.SendEmailResult res : results) { if (res.isSuccess()) { System.debug('Email sent successfully'); } else { sendResult = false; System.debug('The following errors occurred: ' + res.getErrors()); } } return sendResult; } }
基本はこっから起動して
クラスを追加
クラス名は StringArrayTest
答えを書いても仕方ないのでテスト内容の翻訳
StringArrayTest
というクラスでpublic
で作りますpublic static
なメソッドgenerateStringArray
を作成しますgenerateStringArray
の仕様はInteger
型の引数List<String>
型の返値型- 引数の値によって
Test 0
,Test 1
... の様な値を返します。
sObject の使用
Salesforce のデータベースはすべてオブジェクト、Apex 的には sObject
型です。
全てのオブジェクトには Id
フィールドがあり、プライマリキーです。型も ID
型で、18文字 String 値が入ってます。
sObject は Salesforce開発の基礎編2 - 技術をかじる猫 このデータモデリング参照。
クエリもソース内でこんな風に書ける
List<Account> values = [SELECT Id, Name FROM Account WHERE Name LIKE 'Test%'];
DML を使用したレコードの操作
DML ってのは、要するにレコード操作
insert, delete, update, upsert, undelete, merge
でデータを色々いじれる。
Account acct = new Account(Name='Acme', Phone='(415)555-1212', NumberOfEmployees=100); insert acct;
insert
や upsert
した直後に Id
フィールドにだけ値が設定される。
数式項目は insert
が完了したときに埋められる…のだけど、insert
に使ったオブジェクトには入らないので、select
しなおさないといけない。
upsert
は insert
としても update
としても使えるコマンドで、merge
は最大 3 レコードを 1 レコードに自動マージして既存レコードを削除して保存される。
一応データベース操作はメソッドでもできる。
Database.insert() Database.update() Database.upsert() Database.delete() Database.undelete() Database.merge()
問題はこんな内容
AccountHandler
クラスを作成しますpublic
でね- 以下の仕様を満たす
public static
なinsertNewAccount
メソッドを作ります- 引数に
String
を受け取り、Account オブジェクトを作成、Account.Name
に設定します。 - 作ったら
Account
をinsert
し、return
する。 - 引数では空文字も受付け、保存に失敗したら
null
を返します。
- 引数に
SOQL クエリの作成
ソース中にクエリが書ける仕様の演習課題。
public class ContactSearch
を作成してくださいpublic static
なメソッドsearchForContacts
を定義します。- 二つの
String
パラメータを受け取ります Contact
を検索します。第一引数はLastName
とマッチさせ、第二引数はMailingPostalCode
と一致検索します。- 最終的に
List<Contact>
を return します。SELECT 内容は Id, Name です。
- 二つの
Apex トリガ
何故かやたらとお世話になる Apex トリガ。
これはデータベースレコード操作に割り込む処理で、ソースコードで割り込めるあたりが割と便利。
Apex トリガの使用開始
Apex トリガの記述
要するに DML に割り込めるタイミングの説明。
以下のタイミングが扱える。
before insert before update before delete after insert after update after delete after undelete
トリガの設定はこれ見れば分かるはず
trigger HelloWorldTrigger on Account (before insert, after insert) { if (Trriger.isInsert) { if (Trriger.isBefore) { List<Account> values = Trriger.New; } else if (Trigger.isAfter) { List<Account> values = Trriger.New; } } }
before
は実際にデータの操作(insert
等)の直前に実行される。関連するカラムを計算して保存する場合、加工はここ。
after
はデータ操作実行直後に実行される。この時点で Id
等が設定されている。関連するレコードを作成するなどする場合はここ。
因みに、before insert
や after insert
内で Trigger.New
のデータを delete
したりすることはできません。
やるなら after insert
で再度 select
することで delete
等を実行することができます。
また、トリガ内では原則的に Callout
(Callout は外部サーバへのHTTPリクエストの事)は実行できません。
そこで @future(callout=true)
アノテーションのついた非同期処理などを使用することで呼び出すことができます。
一括 Apex トリガ
前述で Trigger.New
が List
返してることを考えれば分かるけど、要するに複数レコードがまとめて入ってくる。
それは insert
でリストを指定していたり、DataLoader
でまとめてどーんしたときに複数入ってきます。
で、ここからが問題で、Salesforce にはガバナ制限つーもんがあります。
developer.salesforce.com
見れば分かるけど、1回の処理で行っていい DML 操作や SELECT 回数には限界がある。
ループしながら SELECT すると、制限の 100 回なんて一瞬な訳で…なので、そういう操作するならまとめて SELECT や一気に操作を心がけましょうという話。
トリガの実行順序なども試験の範囲なんで覚えときせう