
- Apex程式設計教程
- Apex - 首頁
- Apex - 概述
- Apex - 環境
- Apex - 示例
- Apex - 資料型別
- Apex - 變數
- Apex - 字串
- Apex - 陣列
- Apex - 常量
- Apex - 決策
- Apex - 迴圈
- Apex - 集合
- Apex - 類
- Apex - 方法
- Apex - 物件
- Apex - 介面
- Apex - DML
- Apex - 資料庫方法
- Apex - SOSL
- Apex - SOQL
- Apex - 安全性
- Apex - 呼叫
- Apex - 觸發器
- Apex - 觸發器設計模式
- Apex - 限制
- Apex - 批處理
- Apex - 除錯
- Apex - 測試
- Apex - 部署
Apex 快速指南
Apex - 概述
什麼是Apex?
Apex是由Salesforce.com開發的一種專有語言。根據官方定義,Apex是一種強型別、面向物件的程式語言,允許開發人員在Force.com平臺伺服器上執行流程和事務控制語句,並結合對Force.com API的呼叫。
它具有類似Java的語法,並且像資料庫儲存過程一樣工作。它使開發人員能夠向大多數系統事件新增業務邏輯,包括按鈕點選、相關記錄更新和Visualforce頁面。Apex程式碼可以由Web服務請求以及物件上的觸發器啟動。Apex包含在Performance Edition、Unlimited Edition、Enterprise Edition和Developer Edition中。

Apex作為一種語言的特性
現在讓我們討論一下Apex作為一種語言的特性:
整合
Apex內建支援DML操作,如INSERT、UPDATE、DELETE,以及DML異常處理。它支援內聯SOQL和SOSL查詢處理,這些查詢返回sObject記錄集。我們將在以後的章節中詳細學習sObject、SOQL、SOSL。
類似Java的語法,易於使用
Apex易於使用,因為它使用類似Java的語法。例如,變數宣告、迴圈語法和條件語句。
與資料緊密整合
Apex以資料為中心,旨在一起執行多個查詢和DML語句。它在資料庫上發出多個事務語句。
強型別
Apex是一種強型別語言。它使用對架構物件的直接引用,如sObject,如果物件被刪除或資料型別錯誤,任何無效引用都會快速失敗。
多租戶環境
Apex在多租戶環境中執行。因此,Apex執行時引擎旨在嚴格防止程式碼失控,防止它獨佔共享資源。任何違反限制的程式碼都會失敗,並顯示易於理解的錯誤訊息。
自動升級
Apex作為Salesforce版本的一部分進行升級。我們不必手動升級它。
易於測試
Apex為單元測試的建立和執行提供了內建支援,包括指示程式碼覆蓋率的測試結果,以及哪些程式碼部分可以更有效率。
何時選擇Apex?
當我們無法使用預構建的和現有的開箱即用的功能實現複雜的業務功能時,應該使用Apex。以下是在Salesforce配置中需要使用Apex的情況。
Apex應用程式
當我們想要:
建立與其他系統整合的Web服務。
建立用於電子郵件群發或電子郵件設定的電子郵件服務。
對多個物件同時執行復雜的驗證,以及自定義驗證實現。
建立現有工作流功能或流程不支援的複雜業務流程。
建立自定義事務邏輯(在整個事務過程中發生的邏輯,而不僅僅是單個記錄或物件),例如使用資料庫方法更新記錄。
在記錄被修改時執行某些邏輯,或者在某些事件導致觸發器觸發時修改相關物件的記錄。
Apex的工作結構
如下圖所示(參考:Salesforce開發人員文件),Apex完全在按需的Force.com平臺上執行

操作流程
當開發人員儲存程式碼以及終端使用者執行某些操作呼叫Apex程式碼時,有兩種操作序列,如下所示:
開發人員操作
當開發人員將Apex程式碼寫入並儲存到平臺時,平臺應用程式伺服器首先將程式碼編譯成Apex執行時直譯器可以理解的一組指令,然後將這些指令儲存為元資料。
終端使用者操作
當終端使用者透過點選按鈕或訪問Visualforce頁面觸發Apex的執行時,平臺應用程式伺服器從元資料中檢索編譯後的指令,並在返回結果之前透過執行時直譯器傳送它們。與標準應用程式平臺請求相比,終端使用者在執行時間上沒有觀察到任何差異。
由於Apex是Salesforce.com的專有語言,因此它不支援通用程式語言的一些功能。以下是Apex不支援的一些功能:
它無法在使用者介面中顯示元素。
您無法更改標準SFDC提供的功能,也無法阻止標準功能的執行。
建立多個執行緒也不像在其他語言中那樣可能。
理解Apex語法
Apex程式碼通常包含許多我們可能從其他程式語言中熟悉的東西。
變數宣告
作為強型別語言,您必須在Apex中使用資料型別宣告每個變數。如下面的程式碼所示(下面的螢幕截圖),lstAcc被宣告為帳戶列表的資料型別。
SOQL查詢
這將用於從Salesforce資料庫中獲取資料。下面螢幕截圖中顯示的查詢正在從帳戶物件中獲取資料。
迴圈語句
此迴圈語句用於迭代列表或迭代一段程式碼指定次數。在下面螢幕截圖中顯示的程式碼中,迭代次數與我們擁有的記錄數相同。
流程控制語句
If語句用於此程式碼中的流程控制。根據某些條件,決定是繼續執行還是停止執行特定程式碼段。例如,在下面顯示的程式碼中,它正在檢查列表是否為空或是否包含記錄。
DML語句
對資料庫中記錄執行記錄插入、更新、upsert、刪除操作。例如,下面給出的程式碼有助於使用新欄位值更新帳戶。
以下是Apex程式碼片段的外觀示例。我們將在本教程中進一步學習所有這些Apex程式設計概念。

Apex - 環境
在本章中,我們將瞭解Salesforce Apex開發的環境。假設您已經設定了一個用於執行Apex開發的Salesforce版本。
您可以在Salesforce的沙盒或開發人員版本中開發Apex程式碼。沙盒組織是您組織的副本,您可以在其中編寫程式碼並進行測試,而無需承擔資料修改或干擾正常功能的風險。根據標準行業實踐,您必須在沙盒中開發程式碼,然後將其部署到生產環境。
在本教程中,我們將使用Salesforce的開發人員版本。在開發人員版本中,您將沒有建立沙盒組織的選項。沙盒功能在Salesforce的其他版本中可用。

Apex程式碼開發工具
在所有版本中,我們可以使用以下三種工具中的任何一種來開發程式碼:
- Force.com開發人員控制檯
- Force.com IDE
- Salesforce使用者介面中的程式碼編輯器
注意 - 在整個教程中,我們將使用開發人員控制檯來執行程式碼,因為它對於學習來說簡單且使用者友好。
Force.com開發人員控制檯
開發人員控制檯是一個整合開發環境,其中包含您可以用來在Salesforce組織中建立、除錯和測試應用程式的工具集合。
按照以下步驟開啟開發人員控制檯:
步驟1 - 轉到名稱 → 開發人員控制檯

步驟2 - 點選“開發人員控制檯”,將出現一個視窗,如下面的螢幕截圖所示。

以下是使用開發人員控制檯可以執行的一些操作。
編寫和編譯程式碼 - 您可以使用原始碼編輯器編寫程式碼。當您儲存觸發器或類時,程式碼會自動編譯。任何編譯錯誤都將被報告。
除錯 - 您可以使用原始碼編輯器編寫程式碼。當您儲存觸發器或類時,程式碼會自動編譯。任何編譯錯誤都將被報告。
測試 - 您可以檢視除錯日誌並設定有助於除錯的檢查點。
檢查效能 - 您可以執行特定測試類的測試或組織中的所有類,並且可以檢視測試結果。此外,您可以檢查程式碼覆蓋率。
SOQL查詢 - 您可以檢查除錯日誌以查詢效能瓶頸。
顏色編碼和自動完成 - 原始碼編輯器使用顏色方案使程式碼元素更易於閱讀,併為類和方法名稱提供自動完成。
在開發人員控制檯中執行程式碼
本教程中提到的所有程式碼片段都需要在開發人員控制檯中執行。請按照以下步驟在開發人員控制檯中執行步驟。
步驟1 - 使用login.salesforce.com登入到Salesforce.com。複製教程中提到的程式碼片段。目前,我們將使用以下示例程式碼。
String myString = 'MyString'; System.debug('Value of String Variable'+myString);

步驟2 - 要開啟開發人員控制檯,請點選名稱 → 開發人員控制檯,然後點選執行匿名,如下所示。


步驟3 - 在此步驟中,將出現一個視窗,您可以在其中貼上程式碼。

步驟4 - 當我們點選執行時,除錯日誌將開啟。除錯日誌出現在視窗中(如下所示)後,點選日誌記錄。

然後在視窗中鍵入“USER”,如下所示,輸出語句將出現在除錯視窗中。此“USER”語句用於過濾輸出。

因此,基本上,您將按照上述所有步驟在本教程中執行任何程式碼片段。
Apex - 示例
企業應用程式開發示例
在本教程中,我們將為一家化工裝置和加工公司實施CRM應用程式。該公司與供應商打交道並提供服務。在整個教程中,我們將針對此示例制定一些小的程式碼片段,以詳細瞭解每個概念。
要執行本教程中的程式碼,您需要建立兩個物件:客戶物件和發票物件。如果您已經知道如何在 Salesforce 中建立這些物件,則可以跳過以下步驟。否則,您可以按照以下分步指南操作。
建立客戶物件
我們將首先設定客戶物件。
步驟 1 − 轉到設定,然後搜尋“物件”,如下所示。然後單擊下面的“物件”連結。


步驟 2 − 開啟物件頁面後,單擊“建立新物件”按鈕,如下所示。

步驟 3 − 單擊按鈕後,將出現新物件建立頁面,然後輸入如下所示的所有物件詳細資訊。物件名稱應為客戶。您只需在螢幕截圖中所示的欄位中輸入資訊,並將其他預設內容保持原樣。

輸入資訊,然後單擊“儲存”按鈕 −

透過以上步驟,我們已成功建立了客戶物件。
為客戶物件建立自定義欄位
現在我們已經設定了客戶物件,我們將建立一個名為“活動”的欄位,然後您可以按照類似的步驟建立其他欄位。欄位的名稱和 API 名稱將在螢幕截圖中給出。
步驟 1 − 我們將建立一個名為“活動”的欄位,資料型別為複選框。轉到設定並單擊它。

步驟 2 − 搜尋“物件”,如下所示,然後單擊它。

步驟 3 − 單擊物件“客戶”。

步驟 4 − 單擊客戶物件連結並出現物件詳細資訊頁面後,單擊“新建”按鈕。

步驟 5 − 現在,選擇資料型別為複選框,然後單擊“下一步”。

步驟 6 − 輸入欄位名稱和標籤,如下所示。

步驟 7 − 單擊“可見”,然後單擊“下一步”。

步驟 8 − 現在單擊“儲存”。

透過以上步驟,我們建立了自定義欄位“活動”。您必須對其餘欄位遵循所有上述自定義欄位建立步驟。這是建立所有欄位後客戶物件的最終檢視 −

建立發票物件
步驟 1 − 轉到設定,搜尋“物件”,然後單擊下面的“物件”連結。


步驟 2 − 開啟物件頁面後,單擊“建立新物件”按鈕,如下所示。

步驟 3 − 單擊按鈕後,將出現新的物件建立頁面,如下面的螢幕截圖所示。您需要在此處輸入詳細資訊。物件名稱應為發票。這與我們在本教程前面建立客戶物件的方式類似。

步驟 4 − 輸入如下所示的資訊,然後單擊“儲存”按鈕。

按照這些步驟,將建立您的發票物件。
為發票物件建立自定義欄位
我們將如下所示在發票物件上建立欄位“描述”−
步驟 1 − 轉到設定並單擊它。

步驟 2 − 搜尋“物件”,如下所示,然後單擊它。

步驟 3 − 單擊物件“發票”。

然後單擊“新建”。

步驟 4 − 選擇資料型別為文字區域,然後單擊“下一步”按鈕。

步驟 5 − 輸入如下所示的資訊。

步驟 6 − 單擊“可見”,然後單擊“下一步”。

步驟 7 − 單擊“儲存”。

同樣,您可以在發票物件上建立其他欄位。

這樣,我們就建立了本教程所需的多個物件。我們將在後續章節中學習基於這些物件的各種示例。
Apex - 資料型別
瞭解資料型別
Apex 語言是強型別語言,因此 Apex 中的每個變數都將宣告為特定資料型別。所有 apex 變數最初都初始化為 null。始終建議開發人員確保為變數分配正確的值。否則,在使用此類變數時,將引發空指標異常或任何未處理的異常。
Apex 支援以下資料型別 −
原始型別(整數、雙精度數、長整數、日期、日期時間、字串、ID 或布林值)
集合(列表、集合和對映)(將在第 6 章中介紹)
sObject
列舉
類、物件和介面(將在第 11、12 和 13 章中介紹)
在本節中,我們將瞭解所有原始資料型別、sObject 和列舉。我們將分別在後續章節中介紹集合、類、物件和介面,因為它們是需要單獨學習的關鍵主題。
原始資料型別
在本節中,我們將討論 Apex 支援的原始資料型別。
整數
一個 32 位數字,不包含任何小數點。此值的範圍從 -2,147,483,648 開始,最大值為 2,147,483,647。
示例
我們想宣告一個變數,該變數將儲存需要運送到化工處理廠買家的桶的數量。
Integer barrelNumbers = 1000; system.debug(' value of barrelNumbers variable: '+barrelNumbers);
System.debug() 函式列印變數的值,以便我們可以使用它進行除錯或瞭解變數當前儲存的值。
將以上程式碼貼上到開發者控制檯中,然後單擊“執行”。生成日誌後,它將顯示變數“barrelNumbers”的值為 1000。
布林值
此變數可以是 true、false 或 null。很多時候,這種型別的變數可以用作程式設計中的標誌,以識別特定條件是否已設定或未設定。
示例
如果要將布林值 shipmentDispatched 設定為 true,則可以將其宣告為 −
Boolean shipmentDispatched; shipmentDispatched = true; System.debug('Value of shipmentDispatched '+shipmentDispatched);
日期
此變數型別表示日期。它只能儲存日期,不能儲存時間。要儲存日期和時間,我們需要將其儲存在 DateTime 型別的變數中。
示例
請考慮以下示例以瞭解 Date 變數的工作原理。
//ShipmentDate can be stored when shipment is dispatched. Date ShipmentDate = date.today(); System.debug('ShipmentDate '+ShipmentDate);
長整數
這是一個 64 位數字,沒有小數點。當我們需要比整數提供的範圍更寬的值範圍時,可以使用它。
示例
如果要儲存公司收入,則我們將使用 Long 資料型別。
Long companyRevenue = 21474838973344648L; system.debug('companyRevenue'+companyRevenue);
物件
我們可以將其稱為 Apex 支援的任何資料型別。例如,類變數可以是該類的物件,sObject 通用型別也是一個物件,類似地,像 Account 這樣的特定物件型別也是一個物件。
示例
請考慮以下示例以瞭解物件變數的工作原理。
Account objAccount = new Account (Name = 'Test Chemical'); system.debug('Account value'+objAccount);
注意 − 您還可以建立預定義類的物件,如下所示 −
//Class Name: MyApexClass MyApexClass classObj = new MyApexClass();
這是將用作類變數的類物件。
字串
字串是單引號內的任何字元集。它對字元數沒有限制。這裡,將使用堆大小來確定字元數。這限制了 Apex 程式對資源的壟斷,並確保它不會變得太大。
示例
String companyName = 'Abc International'; System.debug('Value companyName variable'+companyName);
時間
此變數用於儲存特定時間。此變數應始終使用系統靜態方法宣告。
Blob
Blob 是儲存為物件的二進位制資料的集合。當我們想將 Salesforce 中的附件儲存到變數中時,將使用它。此資料型別將附件轉換為單個物件。如果要將 Blob 轉換為字串,則可以使用 toString 和 valueOf 方法來實現。
sObject
這是 Salesforce 中的一種特殊資料型別。它類似於 SQL 中的表,包含類似於 SQL 中列的欄位。sObject 有兩種型別:標準和自定義。
例如,帳戶是標準 sObject,任何其他使用者定義的物件(如我們建立的客戶物件)是自定義 sObject。
示例
//Declaring an sObject variable of type Account Account objAccount = new Account(); //Assignment of values to fields of sObjects objAccount.Name = 'ABC Customer'; objAccount.Description = 'Test Account'; System.debug('objAccount variable value'+objAccount); //Declaring an sObject for custom object APEX_Invoice_c APEX_Customer_c objCustomer = new APEX_Customer_c(); //Assigning value to fields objCustomer.APEX_Customer_Decscription_c = 'Test Customer'; System.debug('value objCustomer'+objCustomer);
列舉
列舉是一種抽象資料型別,它儲存指定識別符號的有限集中一個值。您可以使用關鍵字 Enum 定義列舉。列舉可以用作 Salesforce 中的任何其他資料型別。
示例
您可以透過執行以下程式碼來宣告化學化合物的可能名稱 −
//Declaring enum for Chemical Compounds public enum Compounds {HCL, H2SO4, NACL, HG} Compounds objC = Compounds.HCL; System.debug('objC value: '+objC);
Apex - 變數
Java 和 Apex 在很多方面都很相似。Java 和 Apex 中的變數宣告也大致相同。我們將討論一些示例以瞭解如何宣告區域性變數。
String productName = 'HCL'; Integer i = 0; Set<string> setOfProducts = new Set<string>(); Map<id, string> mapOfProductIdToName = new Map<id, string>();
請注意,所有變數都分配了 null 值。
宣告變數
您可以像 String 和 Integer 一樣在 Apex 中宣告變數,如下所示 −
String strName = 'My String'; //String variable declaration Integer myInteger = 1; //Integer variable declaration Boolean mtBoolean = true; //Boolean variable declaration
Apex 變數不區分大小寫
這意味著以下程式碼將引發錯誤,因為變數“m”已聲明瞭兩次,並且兩者都將被視為相同。
Integer m = 100; for (Integer i = 0; i<10; i++) { integer m = 1; //This statement will throw an error as m is being declared again System.debug('This code will throw error'); }
變數的作用域
Apex 變數從其在程式碼中宣告的位置開始有效。因此,不允許在程式碼塊中再次重新定義相同的變數。此外,如果在方法中宣告任何變數,則該變數的作用域將僅限於該特定方法。但是,可以在整個類中訪問類變數。
示例
//Declare variable Products List<string> Products = new List<strings>(); Products.add('HCL'); //You cannot declare this variable in this code clock or sub code block again //If you do so then it will throw the error as the previous variable in scope //Below statement will throw error if declared in same code block List<string> Products = new List<strings>();
Apex - 字串
與任何其他程式語言一樣,Apex 中的字串是任何字元集,沒有字元限制。
示例
String companyName = 'Abc International'; System.debug('Value companyName variable'+companyName);
字串方法
Salesforce 中的 String 類有很多方法。在本節中,我們將介紹一些最重要和最常用的字串方法。
包含
如果給定字串包含提到的子字串,則此方法將返回 true。
語法
public Boolean contains(String substring)
示例
String myProductName1 = 'HCL'; String myProductName2 = 'NAHCL'; Boolean result = myProductName2.contains(myProductName1); System.debug('O/p will be true as it contains the String and Output is:'+result);
等於
如果給定字串和方法中傳遞的字串具有相同的字元二進位制序列,並且它們不為空,則此方法將返回 true。您還可以使用此方法比較 SFDC 記錄 ID。此方法區分大小寫。
語法
public Boolean equals(Object string)
示例
String myString1 = 'MyString'; String myString2 = 'MyString'; Boolean result = myString2.equals(myString1); System.debug('Value of Result will be true as they are same and Result is:'+result);
equalsIgnoreCase
如果 stringtoCompare 與給定字串具有相同的字元序列,則此方法將返回 true。但是,此方法不區分大小寫。
語法
public Boolean equalsIgnoreCase(String stringtoCompare)
示例
以下程式碼將返回 true,因為字串字元和序列相同,忽略大小寫。
String myString1 = 'MySTRING'; String myString2 = 'MyString'; Boolean result = myString2.equalsIgnoreCase(myString1); System.debug('Value of Result will be true as they are same and Result is:'+result);
移除
此方法從給定字串中移除 stringToRemove 中提供的字串。當您想從字串中移除一些特定字元並且不知道要移除的字元的確切索引時,這很有用。此方法區分大小寫,如果出現相同的字元序列但大小寫不同,則不起作用。
語法
public String remove(String stringToRemove)
示例
String myString1 = 'This Is MyString Example'; String stringToRemove = 'MyString'; String result = myString1.remove(stringToRemove); System.debug('Value of Result will be 'This Is Example' as we have removed the MyString and Result is :'+result);
removeEndIgnoreCase
此方法從給定字串中移除 stringToRemove 中提供的字串,但前提是它出現在末尾。此方法不區分大小寫。
語法
public String removeEndIgnoreCase(String stringToRemove)
示例
String myString1 = 'This Is MyString EXAMPLE'; String stringToRemove = 'Example'; String result = myString1.removeEndIgnoreCase(stringToRemove); System.debug('Value of Result will be 'This Is MyString' as we have removed the 'Example' and Result is :'+result);
startsWith
如果給定字串以方法中提供的開頭字串開頭,則此方法將返回 true。
語法
public Boolean startsWith(String prefix)
示例
String myString1 = 'This Is MyString EXAMPLE'; String prefix = 'This'; Boolean result = myString1.startsWith(prefix); System.debug(' This will return true as our String starts with string 'This' and the Result is :'+result);
Apex - 陣列
Apex 中的陣列基本上與 Apex 中的列表相同。陣列和列表之間沒有邏輯區別,因為它們的內部資料結構和方法也相同,但陣列語法有點傳統,類似於 Java。
以下是產品陣列的表示形式 −
索引 0 − HCL
索引 1 − H2SO4
索引 2 − NACL
索引 3 − H2O
索引 4 − N2
索引 5 − U296
語法
<String> [] arrayOfProducts = new List<String>();
示例
假設,我們必須儲存我們產品的名稱 - 我們可以使用陣列,在其中我們將儲存產品名稱,如下所示。您可以透過指定索引來訪問特定產品。
//Defining array String [] arrayOfProducts = new List<String>(); //Adding elements in Array arrayOfProducts.add('HCL'); arrayOfProducts.add('H2SO4'); arrayOfProducts.add('NACL'); arrayOfProducts.add('H2O'); arrayOfProducts.add('N2'); arrayOfProducts.add('U296'); for (Integer i = 0; i<arrayOfProducts.size(); i++) { //This loop will print all the elements in array system.debug('Values In Array: '+arrayOfProducts[i]); }
使用索引訪問陣列元素
您可以使用索引訪問陣列中的任何元素,如下所示 −
//Accessing the element in array //We would access the element at Index 3 System.debug('Value at Index 3 is :'+arrayOfProducts[3]);
Apex - 常量
與任何其他程式語言一樣,常量是在宣告或分配值後不會更改其值的變數。
在 Apex 中,當我們想要定義在整個程式執行過程中應具有常數值的變數時,會使用常量。Apex 常量使用關鍵字“final”宣告。
示例
考慮一個CustomerOperationClass類和其中的常量變數regularCustomerDiscount−
public class CustomerOperationClass { static final Double regularCustomerDiscount = 0.1; static Double finalPrice = 0; public static Double provideDiscount (Integer price) { //calculate the discount finalPrice = price - price * regularCustomerDiscount; return finalPrice; } }
要檢視上述類的輸出,您必須在開發者控制檯匿名視窗中執行以下程式碼 −
Double finalPrice = CustomerOperationClass.provideDiscount(100); System.debug('finalPrice '+finalPrice);
Apex - 決策
決策結構要求程式設計師指定一個或多個條件,由程式進行評估或測試,以及在條件確定為真時要執行的語句或語句,以及可選地,在條件確定為假時要執行的其他語句。
在本章中,我們將學習 Apex 中決策和條件語句的基本和高階結構。決策對於在滿足或不滿足特定條件時控制執行流程是必要的。以下是大多數程式語言中常見的決策結構的一般形式

序號 | 語句及描述 |
---|---|
1 | if 語句
if 語句包含一個布林表示式,後跟一個或多個語句。 |
2 | if...else 語句
if 語句後面可以跟一個可選的else語句,當布林表示式為假時執行。 |
3 | if...elseif...else 語句
if 語句後面可以跟一個可選的else if...else語句,這對於使用單個 if...else if 語句測試各種條件非常有用。 |
4 | 巢狀 if 語句
您可以在另一個if 或 else if語句中使用一個if 或 else if語句。 |
Apex - 迴圈
當需要重複執行一段特定的程式碼並進行所需次數的迭代時,使用迴圈。Apex 支援標準的傳統 for 迴圈以及其他高階型別的迴圈。在本章中,我們將詳細討論 Apex 中的迴圈。
迴圈語句允許我們多次執行一個語句或一組語句,以下是大多數程式語言中迴圈語句的一般形式:

下表列出了處理 Apex 程式語言中迴圈需求的不同迴圈。點選以下連結檢視它們的詳細資訊。
序號 | 迴圈型別及描述 |
---|---|
1 | for 迴圈
此迴圈對記錄集中每個專案執行一組語句。 |
2 | SOQL for 迴圈
直接對 SOQL 查詢返回的記錄集執行一系列語句。 |
3 | 類似 Java 的 for 迴圈
以傳統的類似 Java 的語法執行一系列語句。 |
4 | while 迴圈
在給定條件為真時重複執行一個語句或一組語句。它在執行迴圈體之前測試條件。 |
5 | do...while 迴圈
類似於 while 語句,但它在迴圈體末尾測試條件。 |
Apex - 集合
集合是一種可以儲存多個記錄的變數型別。例如,列表可以儲存多個帳戶物件的記錄。現在讓我們詳細瞭解所有集合型別。
列表
列表可以包含任意數量的原始資料、集合、sObject、使用者定義和內建 Apex 型別的記錄。這是最重要的集合型別之一,它還有一些專門用於列表的系統方法。列表索引始終從 0 開始。這與 Java 中的陣列類似。列表應使用關鍵字“List”宣告。
示例
以下是包含原始資料型別(字串)列表的列表,即城市列表。
List<string> ListOfCities = new List<string>(); System.debug('Value Of ListOfCities'+ListOfCities);
宣告列表的初始值是可選的。但是,我們將在此處宣告初始值。以下是一個顯示相同內容的示例。
List<string> ListOfStates = new List<string> {'NY', 'LA', 'LV'}; System.debug('Value ListOfStates'+ListOfStates);
帳戶列表(sObject)
List<account> AccountToDelete = new List<account> (); //This will be null System.debug('Value AccountToDelete'+AccountToDelete);
我們也可以宣告巢狀列表。它可以最多巢狀五層。這稱為多維列表。
這是整數集合的列表。
List<List<Set<Integer>>> myNestedList = new List<List<Set<Integer>>>(); System.debug('value myNestedList'+myNestedList);
列表可以包含任意數量的記錄,但為了防止效能問題和佔用資源,對堆大小有限制。
列表方法
列表有一些可用的方法,我們在程式設計時可以利用這些方法來實現一些功能,例如計算列表的大小、新增元素等。
以下是一些最常用的方法:
- size()
- add()
- get()
- clear()
- set()
以下示例演示了所有這些方法的使用
// Initialize the List List<string> ListOfStatesMethod = new List<string>(); // This statement would give null as output in Debug logs System.debug('Value of List'+ ListOfStatesMethod); // Add element to the list using add method ListOfStatesMethod.add('New York'); ListOfStatesMethod.add('Ohio'); // This statement would give New York and Ohio as output in Debug logs System.debug('Value of List with new States'+ ListOfStatesMethod); // Get the element at the index 0 String StateAtFirstPosition = ListOfStatesMethod.get(0); // This statement would give New York as output in Debug log System.debug('Value of List at First Position'+ StateAtFirstPosition); // set the element at 1 position ListOfStatesMethod.set(0, 'LA'); // This statement would give output in Debug log System.debug('Value of List with element set at First Position' + ListOfStatesMethod[0]); // Remove all the elements in List ListOfStatesMethod.clear(); // This statement would give output in Debug log System.debug('Value of List'+ ListOfStatesMethod);
您也可以使用陣列表示法來宣告列表,如下所示,但這在 Apex 程式設計中不是一般做法:
String [] ListOfStates = new List<string>();
集合
集合是一種集合型別,它包含多個無序的唯一記錄。集合不能包含重複記錄。與列表一樣,集合也可以巢狀。
示例
我們將定義公司正在銷售的產品集合。
Set<string> ProductSet = new Set<string>{'Phenol', 'Benzene', 'H2SO4'}; System.debug('Value of ProductSet'+ProductSet);
集合方法
集合支援我們在程式設計時可以利用的方法,如下所示(我們正在擴充套件上面的示例):
// Adds an element to the set // Define set if not defined previously Set<string> ProductSet = new Set<string>{'Phenol', 'Benzene', 'H2SO4'}; ProductSet.add('HCL'); System.debug('Set with New Value '+ProductSet); // Removes an element from set ProductSet.remove('HCL'); System.debug('Set with removed value '+ProductSet); // Check whether set contains the particular element or not and returns true or false ProductSet.contains('HCL'); System.debug('Value of Set with all values '+ProductSet);
對映
它是一個鍵值對,每個值都包含唯一的鍵。鍵和值都可以是任何資料型別。
示例
以下示例表示產品名稱與產品程式碼的對映。
// Initialize the Map Map<string, string> ProductCodeToProductName = new Map<string, string> {'1000'=>'HCL', '1001'=>'H2SO4'}; // This statement would give as output as key value pair in Debug log System.debug('value of ProductCodeToProductName'+ProductCodeToProductName);
對映方法
以下是一些演示可與對映一起使用的方法的示例:
// Define a new map Map<string, string> ProductCodeToProductName = new Map<string, string>(); // Insert a new key-value pair in the map where '1002' is key and 'Acetone' is value ProductCodeToProductName.put('1002', 'Acetone'); // Insert a new key-value pair in the map where '1003' is key and 'Ketone' is value ProductCodeToProductName.put('1003', 'Ketone'); // Assert that the map contains a specified key and respective value System.assert(ProductCodeToProductName.containsKey('1002')); System.debug('If output is true then Map contains the key and output is:' + ProductCodeToProductName.containsKey('1002')); // Retrieves a value, given a particular key String value = ProductCodeToProductName.get('1002'); System.debug('Value at the Specified key using get function: '+value); // Return a set that contains all of the keys in the map Set SetOfKeys = ProductCodeToProductName.keySet(); System.debug('Value of Set with Keys '+SetOfKeys);
對映值可能無序,因此我們不應該依賴儲存值的順序,並嘗試始終使用鍵訪問對映。對映值可以為 null。宣告為字串的對映鍵區分大小寫;例如,ABC 和 abc 將被視為不同的鍵並被視為唯一。
Apex - 類
什麼是類?
類是建立物件的模板或藍圖。物件是類的例項。這是類的標準定義。Apex 類類似於 Java 類。
例如,InvoiceProcessor 類描述了包含可以在發票上執行的所有方法和操作的類。如果您建立此類的例項,則它將表示當前處於上下文的單個發票。
建立類
您可以從開發者控制檯、Force.com Eclipse IDE 和 Apex 類詳細資訊頁面建立 Apex 類。
從開發者控制檯
請按照以下步驟從開發者控制檯建立 Apex 類:
步驟 1 - 轉到名稱並點選開發者控制檯。
步驟 2 - 點選檔案 ⇒ 新建,然後點選 Apex 類。

從 Force.com IDE
請按照以下步驟從 Force.com IDE 建立類:
步驟 1 - 開啟 Force.com Eclipse IDE
步驟 2 - 透過點選檔案 ⇒ 新建 ⇒ Apex 類建立新專案。
步驟 3 - 為類提供名稱,然後點選確定。
完成此操作後,將建立新類。
從 Apex 類詳細資訊頁面
請按照以下步驟從 Apex 類詳細資訊頁面建立類:
步驟 1 - 點選名稱 ⇒ 設定。
步驟 2 - 搜尋“Apex 類”並點選連結。它將開啟 Apex 類詳細資訊頁面。

步驟 3 - 點選“新建”,然後為類提供名稱,然後點選儲存。

Apex 類結構
以下是 Apex 類定義的示例結構。
語法
private | public | global [virtual | abstract | with sharing | without sharing] class ClassName [implements InterfaceNameList] [extends ClassName] { // Classs Body }
此定義結合使用了訪問修飾符、共享模式、類名和類體。我們將在後面詳細瞭解所有這些選項。
示例
以下是 Apex 類定義的示例結構:
public class MySampleApexClass { //Class definition and body public static Integer myValue = 0; //Class Member variable public static String myString = ''; //Class Member variable public static Integer getCalculatedValue () { // Method definition and body // do some calculation myValue = myValue+10; return myValue; } }
訪問修飾符
私有
如果將訪問修飾符宣告為“私有”,則此類僅在本地範圍內可見,並且您無法在此特定部分之外訪問此類。預設情況下,類具有此修飾符。
公共
如果將類宣告為“公共”,則表示此類可供您的組織和您定義的名稱空間訪問。通常,大多數 Apex 類都使用此關鍵字定義。
全域性
如果將類宣告為“全域性”,則所有 Apex 程式碼都將可以訪問它,無論您的組織如何。如果您有使用 web service 關鍵字定義的方法,則必須使用 global 關鍵字宣告包含類。
共享模式
現在讓我們討論不同的共享模式。
使用共享
這是 Salesforce 中 Apex 類的一項特殊功能。當使用“使用共享”關鍵字指定類時,它具有以下含義:當類執行時,它將尊重使用者的訪問設定和配置檔案許可權。假設,使用者的操作觸發了 30 條記錄的記錄更新,但使用者只能訪問 20 條記錄,而 10 條記錄無法訪問。然後,如果類正在執行更新記錄的操作,則只會更新使用者有權訪問的 20 條記錄,其餘 10 條記錄將不會更新。這也被稱為使用者模式。
不使用共享
即使使用者無法訪問 30 條記錄中的 10 條,所有 30 條記錄都將被更新,因為類在系統模式下執行,即它已使用“不使用共享”關鍵字定義。這稱為系統模式。
虛擬
如果您使用“虛擬”關鍵字,則表示此類可以擴充套件並且允許覆蓋。如果需要覆蓋方法,則應使用 virtual 關鍵字宣告類。
抽象
如果將類宣告為“抽象”,則它僅包含方法的簽名,而不包含實際的實現。
類變數
語法
[public | private | protected | global] [final] [static] data_type variable_name [= value]
在上述語法中:
- 變數資料型別和變數名稱是必須的
- 訪問修飾符和值是可選的。
示例
public static final Integer myvalue;
Apex - 方法
類方法
Apex 中類方法有兩個修飾符:公共或受保護。方法的返回型別是必須的,如果方法不返回任何內容,則必須將 void 作為返回型別。此外,方法也需要主體。
語法
[public | private | protected | global] [override] [static] return_data_type method_name (input parameters) { // Method body goes here }
語法的解釋
方括號中提到的那些引數是可選的。但是,以下元件是必不可少的:
- return_data_type
- method_name
類方法的訪問修飾符
使用訪問修飾符,您可以指定類方法的訪問級別。例如,公共方法可以在類的任何位置以及類外部訪問。私有方法只能在類內部訪問。全域性方法可以被所有 Apex 類訪問,並且可以作為其他 Apex 類可以訪問的 web service 方法公開。
示例
//Method definition and body public static Integer getCalculatedValue () { //do some calculation myValue = myValue+10; return myValue; }
此方法的返回型別為 Integer,並且不帶引數。
方法可以帶引數,如下例所示:
// Method definition and body, this method takes parameter price which will then be used // in method. public static Integer getCalculatedValueViaPrice (Decimal price) { // do some calculation myValue = myValue+price; return myValue; }
類建構函式
建構函式是在從類藍圖建立物件時呼叫的程式碼。它與類名相同。
我們不需要為每個類都定義建構函式,因為預設情況下會呼叫無引數建構函式。建構函式用於初始化變數或在類初始化時執行某個過程。例如,您可能希望在呼叫類時將某些 Integer 變數的值分配為 0。
示例
// Class definition and body public class MySampleApexClass2 { public static Double myValue; // Class Member variable public static String myString; // Class Member variable public MySampleApexClass2 () { myValue = 100; //initialized variable when class is called } public static Double getCalculatedValue () { // Method definition and body // do some calculation myValue = myValue+10; return myValue; } public static Double getCalculatedValueViaPrice (Decimal price) { // Method definition and body // do some calculation myValue = myValue+price; // Final Price would be 100+100=200.00 return myValue; } }
您也可以透過建構函式呼叫類的方法。這在為 Visualforce 控制器編寫 Apex 程式碼時可能很有用。當建立類物件時,將呼叫建構函式,如下所示:
// Class and constructor has been instantiated MySampleApexClass2 objClass = new MySampleApexClass2(); Double FinalPrice = MySampleApexClass2.getCalculatedValueViaPrice(100); System.debug('FinalPrice: '+FinalPrice);
建構函式過載
建構函式可以過載,即一個類可以定義多個具有不同引數的建構函式。
示例
public class MySampleApexClass3 { // Class definition and body public static Double myValue; // Class Member variable public static String myString; // Class Member variable public MySampleApexClass3 () { myValue = 100; // initialized variable when class is called System.debug('myValue variable with no Overaloading'+myValue); } public MySampleApexClass3 (Integer newPrice) { // Overloaded constructor myValue = newPrice; // initialized variable when class is called System.debug('myValue variable with Overaloading'+myValue); } public static Double getCalculatedValue () { // Method definition and body // do some calculation myValue = myValue+10; return myValue; } public static Double getCalculatedValueViaPrice (Decimal price) { // Method definition and body // do some calculation myValue = myValue+price; return myValue; } }
您可以像在前面的示例中執行它一樣執行此類。
// Developer Console Code MySampleApexClass3 objClass = new MySampleApexClass3(); Double FinalPrice = MySampleApexClass3.getCalculatedValueViaPrice(100); System.debug('FinalPrice: '+FinalPrice);
Apex - 物件
類的例項稱為物件。在 Salesforce 方面,物件可以是類,也可以建立 sObject 的物件。
從類建立物件
您可以像在 Java 或其他面向物件程式語言中一樣建立類物件。
以下是一個名為 MyClass 的示例類:
// Sample Class Example public class MyClass { Integer myInteger = 10; public void myMethod (Integer multiplier) { Integer multiplicationResult; multiplicationResult = multiplier*myInteger; System.debug('Multiplication is '+multiplicationResult); } }
這是一個例項類,即要呼叫或訪問此類的變數或方法,必須建立此類的例項,然後才能執行所有操作。
// Object Creation // Creating an object of class MyClass objClass = new MyClass(); // Calling Class method using Class instance objClass.myMethod(100);
sObject 建立
sObject 是 Salesforce 中儲存資料的物件。例如,Account、Contact 等都是自定義物件。您可以建立這些 sObject 的物件例項。
下面是一個 sObject 初始化的示例,並展示瞭如何使用點表示法訪問該特定物件的欄位並將值分配給欄位。
// Execute the below code in Developer console by simply pasting it // Standard Object Initialization for Account sObject Account objAccount = new Account(); // Object initialization objAccount.Name = 'Testr Account'; // Assigning the value to field Name of Account objAccount.Description = 'Test Account'; insert objAccount; // Creating record using DML System.debug('Records Has been created '+objAccount); // Custom sObject initialization and assignment of values to field APEX_Customer_c objCustomer = new APEX_Customer_c (); objCustomer.Name = 'ABC Customer'; objCustomer.APEX_Customer_Decscription_c = 'Test Description'; insert objCustomer; System.debug('Records Has been created '+objCustomer);
靜態初始化
靜態方法和變數僅在載入類時初始化一次。靜態變數不會作為 Visualforce 頁面的檢視狀態的一部分進行傳輸。
下面是靜態方法和靜態變數的示例。
// Sample Class Example with Static Method public class MyStaticClass { Static Integer myInteger = 10; public static void myMethod (Integer multiplier) { Integer multiplicationResult; multiplicationResult = multiplier * myInteger; System.debug('Multiplication is '+multiplicationResult); } } // Calling the Class Method using Class Name and not using the instance object MyStaticClass.myMethod(100);
靜態變數的使用
靜態變數僅在載入類時例項化一次,這種現象可以用來避免觸發器遞迴。靜態變數值在同一執行上下文中將相同,並且任何正在執行的類、觸發器或程式碼都可以引用它並防止遞迴。
Apex - 介面
介面就像一個 Apex 類,其中沒有一個方法被實現。它只包含方法簽名,但每個方法的主體都是空的。要使用介面,另一個類必須透過為介面中包含的所有方法提供主體來實現它。
介面主要用於為您的程式碼提供抽象層。它們將實現與方法的宣告分開。
讓我們以我們的化工公司的例子為例。假設我們需要為高階客戶和普通客戶提供折扣,並且兩者的折扣將不同。
我們將建立一個名為 **DiscountProcessor** 的介面。
// Interface public interface DiscountProcessor { Double percentageDiscountTobeApplied(); // method signature only } // Premium Customer Class public class PremiumCustomer implements DiscountProcessor { //Method Call public Double percentageDiscountTobeApplied () { // For Premium customer, discount should be 30% return 0.30; } } // Normal Customer Class public class NormalCustomer implements DiscountProcessor { // Method Call public Double percentageDiscountTobeApplied () { // For Premium customer, discount should be 10% return 0.10; } }
當您實現介面時,必須實現該介面的方法。如果您沒有實現介面方法,它將丟擲錯誤。當您希望強制開發人員實現方法時,應該使用介面。
批次 Apex 的標準 Salesforce 介面
SFDC 確實有標準介面,如 Database.Batchable、Schedulable 等。例如,如果您實現了 Database.Batchable 介面,則必須實現介面中定義的三個方法 - Start、Execute 和 Finish。
下面是標準 Salesforce 提供的 Database.Batchable 介面的示例,該介面向用戶傳送包含批處理狀態的電子郵件。此介面有 3 個方法,Start、Execute 和 Finish。使用此介面,我們可以實現 Batchable 功能,它還提供 BatchableContext 變數,我們可以使用它來獲取有關正在執行的批處理的更多資訊並執行其他功能。
global class CustomerProessingBatch implements Database.Batchable<sobject7>, Schedulable { // Add here your email address global String [] email = new String[] {'test@test.com'}; // Start Method global Database.Querylocator start (Database.BatchableContext BC) { // This is the Query which will determine the scope of Records and fetching the same return Database.getQueryLocator('Select id, Name, APEX_Customer_Status__c, APEX_Customer_Decscription__c From APEX_Customer__c WHERE createdDate = today && APEX_Active__c = true'); } // Execute method global void execute (Database.BatchableContext BC, List<sobject> scope) { List<apex_customer__c> customerList = new List<apex_customer__c>(); List<apex_customer__c> updtaedCustomerList = new List<apex_customer__c>(); for (sObject objScope: scope) { // type casting from generic sOject to APEX_Customer__c APEX_Customer__c newObjScope = (APEX_Customer__c)objScope ; newObjScope.APEX_Customer_Decscription__c = 'Updated Via Batch Job'; newObjScope.APEX_Customer_Status__c = 'Processed'; // Add records to the List updtaedCustomerList.add(newObjScope); } // Check if List is empty or not if (updtaedCustomerList != null && updtaedCustomerList.size()>0) { // Update the Records Database.update(updtaedCustomerList); System.debug('List Size '+updtaedCustomerList.size()); } } // Finish Method global void finish(Database.BatchableContext BC) { Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage(); // get the job Id AsyncApexJob a = [Select a.TotalJobItems, a.Status, a.NumberOfErrors, a.JobType, a.JobItemsProcessed, a.ExtendedStatus, a.CreatedById, a.CompletedDate From AsyncApexJob a WHERE id = :BC.getJobId()]; System.debug('$$$ Jobid is'+BC.getJobId()); // below code will send an email to User about the status mail.setToAddresses(email); // Add here your email address mail.setReplyTo('test@test.com'); mail.setSenderDisplayName('Apex Batch Processing Module'); mail.setSubject('Batch Processing '+a.Status); mail.setPlainTextBody('The Batch Apex job processed '+a.TotalJobItems+'batches with '+a.NumberOfErrors+'failures'+'Job Item processed are'+a.JobItemsProcessed); Messaging.sendEmail(new Messaging.Singleemailmessage [] {mail}); } // Scheduler Method to scedule the class global void execute(SchedulableContext sc) { CustomerProessingBatch conInstance = new CustomerProessingBatch(); database.executebatch(conInstance,100); } }
要執行此類,您必須在開發人員控制檯中執行以下程式碼。
CustomerProessingBatch objBatch = new CustomerProessingBatch (); Database.executeBatch(objBatch);
Apex - DML
在本章中,我們將討論如何在 Salesforce 中執行不同的資料庫修改功能。有兩種方法可以執行這些功能。
DML 語句
DML 是為了執行插入、更新、刪除、Upsert、恢復記錄、合併記錄或轉換潛在客戶操作而執行的操作。
DML 是 Apex 中最重要的部分之一,因為幾乎每個業務案例都涉及到對資料庫的更改和修改。
資料庫方法
您可以使用 DML 語句執行的所有操作也可以使用資料庫方法執行。資料庫方法是您可以用來執行 DML 操作的系統方法。與 DML 語句相比,資料庫方法提供了更大的靈活性。
在本章中,我們將首先使用 DML 語句進行探討。我們將在後續章節中介紹資料庫方法。
DML 語句
現在讓我們再次考慮化工供應商公司的例項。我們的發票記錄具有以下欄位:狀態、已付金額、剩餘金額、下次付款日期和發票編號。今天建立且狀態為“待處理”的發票應更新為“已付款”。
插入操作
插入操作用於在資料庫中建立新記錄。您可以使用 Insert DML 語句建立任何標準或自定義物件的記錄。
示例
當每天為新的客戶訂單生成新發票時,我們可以在 APEX_Invoice__c 物件中建立新記錄。我們將首先建立一個客戶記錄,然後我們可以為該新客戶記錄建立一個發票記錄。
// fetch the invoices created today, Note, you must have at least one invoice // created today List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c, createdDate FROM APEX_Invoice__c WHERE createdDate = today]; // create List to hold the updated invoice records List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>(); APEX_Customer__c objCust = new APEX_Customer__C(); objCust.Name = 'Test ABC'; //DML for Inserting the new Customer Records insert objCust; for (APEX_Invoice__c objInvoice: invoiceList) { if (objInvoice.APEX_Status__c == 'Pending') { objInvoice.APEX_Status__c = 'Paid'; updatedInvoiceList.add(objInvoice); } } // DML Statement to update the invoice status update updatedInvoiceList; // Prints the value of updated invoices System.debug('List has been updated and updated values are' + updatedInvoiceList); // Inserting the New Records using insert DML statement APEX_Invoice__c objNewInvoice = new APEX_Invoice__c(); objNewInvoice.APEX_Status__c = 'Pending'; objNewInvoice.APEX_Amount_Paid__c = 1000; objNewInvoice.APEX_Customer__c = objCust.id; // DML which is creating the new Invoice record which will be linked with newly // created Customer record insert objNewInvoice; System.debug('New Invoice Id is '+objNewInvoice.id+' and the Invoice Number is' + objNewInvoice.Name);
更新操作
更新操作是對現有記錄執行更新。在此示例中,我們將更新現有發票記錄的狀態欄位為“已付款”。
示例
// Update Statement Example for updating the invoice status. You have to create and Invoice records before executing this code. This program is updating the record which is at index 0th position of the List. // First, fetch the invoice created today List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c, createdDate FROM APEX_Invoice__c]; List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>(); // Update the first record in the List invoiceList[0].APEX_Status__c = 'Pending'; updatedInvoiceList.add(invoiceList[0]); // DML Statement to update the invoice status update updatedInvoiceList; // Prints the value of updated invoices System.debug('List has been updated and updated values of records are' + updatedInvoiceList[0]);
Upsert 操作
Upsert 操作用於執行更新操作,如果要更新的記錄不存在於資料庫中,則也建立新記錄。
示例
假設,需要更新客戶物件中的客戶記錄。如果現有客戶記錄已存在,我們將更新它,否則建立一個新的。這將基於欄位 APEX_External_Id__c 的值。此欄位將是我們用於識別記錄是否已存在的欄位。
**注意** - 在執行此程式碼之前,請在客戶物件中建立一個外部 ID 欄位值為“12341”的記錄,然後執行以下程式碼 -
// Example for upserting the Customer records List<apex_customer__c> CustomerList = new List<apex_customer__c>(); for (Integer i = 0; i < 10; i++) { apex_customer__c objcust=new apex_customer__c(name = 'Test' +i, apex_external_id__c='1234' +i); customerlist.add(objcust); } //Upserting the Customer Records upsert CustomerList; System.debug('Code iterated for 10 times and created 9 records as one record with External Id 12341 is already present'); for (APEX_Customer_c objCustomer: CustomerList) { if (objCustomer.APEX_External_Id_c == '12341') { system.debug('The Record which is already present is '+objCustomer); } }
刪除操作
您可以使用 Delete DML 執行刪除操作。
示例
在這種情況下,我們將刪除為測試目的建立的發票,即名稱為“測試”的發票。
您也可以從開發人員控制檯中執行此程式碼段,而無需建立類。
// fetch the invoice created today List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c, createdDate FROM APEX_Invoice__c WHERE createdDate = today]; List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>(); APEX_Customer__c objCust = new APEX_Customer__C(); objCust.Name = 'Test'; // Inserting the Customer Records insert objCust; for (APEX_Invoice__c objInvoice: invoiceList) { if (objInvoice.APEX_Status__c == 'Pending') { objInvoice.APEX_Status__c = 'Paid'; updatedInvoiceList.add(objInvoice); } } // DML Statement to update the invoice status update updatedInvoiceList; // Prints the value of updated invoices System.debug('List has been updated and updated values are' + updatedInvoiceList); // Inserting the New Records using insert DML statement APEX_Invoice__c objNewInvoice = new APEX_Invoice__c(); objNewInvoice.APEX_Status__c = 'Pending'; objNewInvoice.APEX_Amount_Paid__c = 1000; objNewInvoice.APEX_Customer__c = objCust.id; // DML which is creating the new record insert objNewInvoice; System.debug('New Invoice Id is' + objNewInvoice.id); // Deleting the Test invoices from Database // fetch the invoices which are created for Testing, Select name which Customer Name // is Test. List<apex_invoice__c> invoiceListToDelete = [SELECT id FROM APEX_Invoice__c WHERE APEX_Customer__r.Name = 'Test']; // DML Statement to delete the Invoices delete invoiceListToDelete; System.debug('Success, '+invoiceListToDelete.size()+' Records has been deleted');
撤銷刪除操作
您可以撤銷已刪除且存在於回收站中的記錄。已刪除記錄具有的所有關係也將被恢復。
示例
假設,需要恢復上一個示例中刪除的記錄。這可以透過以下示例實現。上一個示例中的程式碼已為此示例修改。
// fetch the invoice created today List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c, createdDate FROM APEX_Invoice__c WHERE createdDate = today]; List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>(); APEX_Customer__c objCust = new APEX_Customer__C(); objCust.Name = 'Test'; // Inserting the Customer Records insert objCust; for (APEX_Invoice__c objInvoice: invoiceList) { if (objInvoice.APEX_Status__c == 'Pending') { objInvoice.APEX_Status__c = 'Paid'; updatedInvoiceList.add(objInvoice); } } // DML Statement to update the invoice status update updatedInvoiceList; // Prints the value of updated invoices System.debug('List has been updated and updated values are' + updatedInvoiceList); // Inserting the New Records using insert DML statement APEX_Invoice__c objNewInvoice = new APEX_Invoice__c(); objNewInvoice.APEX_Status__c = 'Pending'; objNewInvoice.APEX_Amount_Paid__c = 1000; objNewInvoice.APEX_Customer__c = objCust.id; // DML which is creating the new record insert objNewInvoice; System.debug('New Invoice Id is '+objNewInvoice.id); // Deleting the Test invoices from Database // fetch the invoices which are created for Testing, Select name which Customer Name // is Test. List<apex_invoice__c> invoiceListToDelete = [SELECT id FROM APEX_Invoice__c WHERE APEX_Customer__r.Name = 'Test']; // DML Statement to delete the Invoices delete invoiceListToDelete; system.debug('Deleted Record Count is ' + invoiceListToDelete.size()); System.debug('Success, '+invoiceListToDelete.size() + 'Records has been deleted'); // Restore the deleted records using undelete statement undelete invoiceListToDelete; System.debug('Undeleted Record count is '+invoiceListToDelete.size()+'. This should be same as Deleted Record count');
Apex - 資料庫方法
資料庫類方法是使用 DML 語句的另一種方法,它比 DML 語句(如插入、更新等)更靈活。
資料庫方法和 DML 語句的區別
DML 語句 | 資料庫方法 |
---|---|
不允許部分更新。例如,如果列表中有 20 條記錄,則要麼所有記錄都將更新,要麼都不更新。 | 允許部分更新。您可以在資料庫方法中將引數指定為 true 或 false,true 表示允許部分更新,false 表示不允許部分更新。 |
您無法獲取成功和失敗記錄的列表。 | 您可以獲取成功和失敗記錄的列表,如我們在示例中所見。 |
**示例** - insert listName | **示例** - Database.insert(listName, False),其中 false 表示不允許部分更新。 |
插入操作
透過資料庫方法插入新記錄也非常簡單和靈活。讓我們考慮之前的場景,我們在其中使用 DML 語句插入了新記錄。我們將使用資料庫方法插入相同的記錄。
示例
// Insert Operation Using Database methods // Insert Customer Records First using simple DML Statement. This Customer Record will be // used when we will create Invoice Records APEX_Customer__c objCust = new APEX_Customer__C(); objCust.Name = 'Test'; insert objCust; // Inserting the Customer Records // Insert Operation Using Database methods APEX_Invoice__c objNewInvoice = new APEX_Invoice__c(); List<apex_invoice__c> InvoiceListToInsert = new List<apex_invoice__c>(); objNewInvoice.APEX_Status__c = 'Pending'; objNewInvoice.APEX_Customer__c = objCust.id; objNewInvoice.APEX_Amount_Paid__c = 1000; InvoiceListToInsert.add(objNewInvoice); Database.SaveResult[] srList = Database.insert(InvoiceListToInsert, false); // Database method to insert the records in List // Iterate through each returned result by the method for (Database.SaveResult sr : srList) { if (sr.isSuccess()) { // This condition will be executed for successful records and will fetch the ids // of successful records System.debug('Successfully inserted Invoice. Invoice ID: ' + sr.getId()); // Get the invoice id of inserted Account } else { // This condition will be executed for failed records for(Database.Error objErr : sr.getErrors()) { System.debug('The following error has occurred.'); // Printing error message in Debug log System.debug(objErr.getStatusCode() + ': ' + objErr.getMessage()); System.debug('Invoice oject field which are affected by the error:' + objErr.getFields()); } } }
更新操作
現在讓我們使用資料庫方法考慮我們的業務案例示例。假設我們需要更新發票物件的狀態欄位,但同時我們還需要記錄狀態、失敗記錄 ID、成功計數等資訊。這無法透過使用 DML 語句實現,因此我們必須使用資料庫方法來獲取操作的狀態。
示例
如果發票的狀態為“待處理”且建立日期為今天,我們將更新其“狀態”欄位。
以下程式碼將幫助使用 Database.update 方法更新發票記錄。此外,在執行此程式碼之前,請建立一個發票記錄。
// Code to update the records using the Database methods List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c, createdDate FROM APEX_Invoice__c WHERE createdDate = today]; // fetch the invoice created today List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>(); for (APEX_Invoice__c objInvoice: invoiceList) { if (objInvoice.APEX_Status__c == 'Pending') { objInvoice.APEX_Status__c = 'Paid'; updatedInvoiceList.add(objInvoice); //Adding records to the list } } Database.SaveResult[] srList = Database.update(updatedInvoiceList, false); // Database method to update the records in List // Iterate through each returned result by the method for (Database.SaveResult sr : srList) { if (sr.isSuccess()) { // This condition will be executed for successful records and will fetch // the ids of successful records System.debug('Successfully updated Invoice. Invoice ID is : ' + sr.getId()); } else { // This condition will be executed for failed records for(Database.Error objErr : sr.getErrors()) { System.debug('The following error has occurred.'); // Printing error message in Debug log System.debug(objErr.getStatusCode() + ': ' + objErr.getMessage()); System.debug('Invoice oject field which are affected by the error:' + objErr.getFields()); } } }
在本教程中,我們將僅介紹插入和更新操作。其他操作與此操作非常相似,並且與我們在上一章中所做的操作相同。
Apex - SOSL
每個業務或應用程式都將搜尋功能作為基本需求之一。為此,Salesforce.com 提供了兩種主要方法:使用 SOSL 和 SOQL。讓我們在本節中詳細討論 SOSL 方法。
SOSL
使用 SOSL 可以跨物件和跨欄位搜尋文字字串。這是 Salesforce 物件搜尋語言。它能夠跨多個物件搜尋特定字串。
SOSL 語句計算結果為 sObject 列表,其中每個列表包含特定 sObject 型別的搜尋結果。結果列表始終按其在 SOSL 查詢中指定的順序返回。
SOSL 查詢示例
考慮一個業務案例,我們需要開發一個可以搜尋指定字串的程式。假設我們需要在發票物件的客戶名稱欄位中搜索字串“ABC”。程式碼如下所示 -
首先,您必須在發票物件中建立一個單條記錄,客戶名稱為“ABC”,以便在搜尋時獲得有效結果。
// Program To Search the given string in all Object // List to hold the returned results of sObject generic type List<list<SObject>> invoiceSearchList = new List<List<SObject>>(); // SOSL query which will search for 'ABC' string in Customer Name field of Invoice Object invoiceSearchList = [FIND 'ABC*' IN ALL FIELDS RETURNING APEX_Invoice_c (Id,APEX_Customer_r.Name)]; // Returned result will be printed System.debug('Search Result '+invoiceSearchList); // Now suppose, you would like to search string 'ABC' in two objects, // that is Invoice and Account. Then for this query goes like this: // Program To Search the given string in Invoice and Account object, // you could specify more objects if you want, create an Account with Name as ABC. // List to hold the returned results of sObject generic type List<List<SObject>> invoiceAndSearchList = new List<List<SObject>>(); // SOSL query which will search for 'ABC' string in Invoice and in Account object's fields invoiceAndSearchList = [FIND 'ABC*' IN ALL FIELDS RETURNING APEX_Invoice__c (Id,APEX_Customer__r.Name), Account]; // Returned result will be printed System.debug('Search Result '+invoiceAndSearchList); // This list will hold the returned results for Invoice Object APEX_Invoice__c [] searchedInvoice = ((List<APEX_Invoice_c>)invoiceAndSearchList[0]); // This list will hold the returned results for Account Object Account [] searchedAccount = ((List<Account>)invoiceAndSearchList[1]); System.debug('Value of searchedInvoice'+searchedInvoice+'Value of searchedAccount' + searchedAccount);
SOQL
這幾乎與 SOQL 相同。您可以使用它一次僅從一個物件中獲取物件記錄。您可以編寫巢狀查詢,還可以從您現在正在查詢的父物件或子物件中獲取記錄。
我們將在下一章中探討 SOQL。
Apex - SOQL
這是 Salesforce 物件查詢語言,旨在與 SFDC 資料庫配合使用。它只能在單個 sObject 中根據給定條件搜尋記錄。
與 SOSL 類似,它不能跨多個物件搜尋,但它支援巢狀查詢。
SOQL 示例
考慮我們正在進行的化工公司示例。假設我們需要今天建立且客戶名稱不為“測試”的記錄列表。在這種情況下,我們將必須使用以下 SOQL 查詢 -
// fetching the Records via SOQL List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>(); InvoiceList = [SELECT Id, Name, APEX_Customer__r.Name, APEX_Status__c FROM APEX_Invoice__c WHERE createdDate = today AND APEX_Customer__r.Name != 'Test']; // SOQL query for given criteria // Printing the fetched records System.debug('We have total '+InvoiceList.size()+' Records in List'); for (APEX_Invoice__c objInvoice: InvoiceList) { System.debug('Record Value is '+objInvoice); // Printing the Record fetched }
您可以透過開發人員控制檯中的查詢編輯器執行 SOQL 查詢,如下所示。
在開發人員控制檯中執行以下查詢。搜尋今天建立的發票記錄。
SELECT Id, Name, APEX_Customer__r.Name, APEX_Status__c FROM APEX_Invoice__c WHERE createdDate = today
您必須選擇需要值的欄位,否則可能會丟擲執行時錯誤。
遍歷關係欄位
這是 SFDC 中最重要的部分之一,因為很多時候我們需要遍歷父子物件關係
此外,您可能需要在資料庫中插入兩個關聯的物件記錄。例如,Invoice 物件與 Customer 物件存在關聯關係,因此一個客戶可以擁有多個發票。
假設您正在建立發票,然後需要將此發票與客戶關聯。您可以使用以下程式碼實現此功能:
// Now create the invoice record and relate it with the Customer object // Before executing this, please create a Customer Records with Name 'Customer // Creation Test' APEX_Invoice__c objInvoice = new APEX_Invoice__c(); // Relating Invoice to customer via id field of Customer object objInvoice.APEX_Customer__c = [SELECT id FROM APEX_Customer__c WHERE Name = 'Customer Creation Test' LIMIT 1].id; objInvoice.APEX_Status__c = 'Pending'; insert objInvoice; //Creating Invoice System.debug('Newly Created Invoice'+objInvoice); //Newly created invoice
在開發者控制檯中執行此程式碼片段。執行完成後,從開發者控制檯中複製發票的 Id,然後在 SFDC 中開啟相同的記錄,如下所示。您可以看到父記錄已分配給發票記錄,如下所示。

獲取子記錄
現在讓我們考慮一個示例,其中需要將與特定客戶記錄相關的所有發票放在一個地方。為此,您必須知道子關係名稱。要檢視子關係名稱,請轉到子物件上的欄位詳細資訊頁面並檢查“子關係”值。在我們的示例中,它是 invoices,後面附加了 __r。
示例
在此示例中,我們需要設定資料,建立一個名為“ABC 客戶”的客戶記錄,然後向該客戶新增 3 張發票。
現在,我們將獲取客戶“ABC 客戶”擁有的發票。以下是相應的查詢:
// Fetching Child Records using SOQL List<apex_customer__c> ListCustomers = [SELECT Name, Id, (SELECT id, Name FROM Invoices__r) FROM APEX_Customer__c WHERE Name = 'ABC Customer']; // Query for fetching the Child records along with Parent System.debug('ListCustomers '+ListCustomers); // Parent Record List<apex_invoice__c> ListOfInvoices = ListCustomers[0].Invoices__r; // By this notation, you could fetch the child records and save it in List System.debug('ListOfInvoices values of Child '+ListOfInvoices); // Child records
您可以在除錯日誌中檢視記錄值。
獲取父記錄
假設您需要獲取建立日期為今天的發票的客戶名稱,則可以使用以下查詢:
示例
獲取父記錄的值以及子物件。
// Fetching Parent Record Field value using SOQL List<apex_invoice__c> ListOfInvoicesWithCustomerName = new List<apex_invoice__c>(); ListOfInvoicesWithCustomerName = [SELECT Name, id, APEX_Customer__r.Name FROM APEX_Invoice__c LIMIT 10]; // Fetching the Parent record's values for (APEX_Invoice__c objInv: ListOfInvoicesWithCustomerName) { System.debug('Invoice Customer Name is '+objInv.APEX_Customer__r.Name); // Will print the values, all the Customer Records will be printed }
這裡我們使用了 APEX_Customer__r.Name 的表示法,其中 APEX_Customer__r 是父關係名稱,這裡您需要在父欄位的末尾附加 __r,然後您可以獲取父欄位的值。
聚合函式
SOQL 與 SQL 中一樣,也具有聚合函式。聚合函式允許我們彙總和概括資料。現在讓我們詳細瞭解一下該函式。
假設您想知道從“ABC 客戶”那裡獲得的平均收入是多少,則可以使用此函式來計算平均值。
示例
// Getting Average of all the invoices for a Perticular Customer AggregateResult[] groupedResults = [SELECT AVG(APEX_Amount_Paid__c)averageAmount FROM APEX_Invoice__c WHERE APEX_Customer__r.Name = 'ABC Customer']; Object avgPaidAmount = groupedResults[0].get('averageAmount'); System.debug('Total Average Amount Received From Customer ABC is '+avgPaidAmount);
檢查除錯日誌中的輸出。請注意,任何包含聚合函式的查詢都會將其結果返回到一個 **AggregateResult** 物件陣列中。AggregateResult 是一個只讀的 sObject,僅用於查詢結果。當我們需要生成大型資料的報表時,它非常有用。
還有其他聚合函式,您可以使用它們來執行資料彙總。
**MIN()** - 這可以用來查詢最小值。
**MAX()** - 這可以用來查詢最大值。
繫結 Apex 變數
您可以在 SOQL 查詢中使用 Apex 變數來獲取所需的結果。可以使用冒號 (:) 表示法引用 Apex 變數。
示例
// Apex Variable Reference String CustomerName = 'ABC Customer'; List<apex_customer__c> ListCustomer = [SELECT Id, Name FROM APEX_Customer__c WHERE Name = :CustomerName]; // Query Using Apex variable System.debug('ListCustomer Name'+ListCustomer); // Customer Name
Apex - 安全性
Apex 安全性是指在執行程式碼時應用安全設定並強制執行共享規則的過程。Apex 類具有可以透過兩個關鍵字控制的安全設定。
資料安全性和共享規則
Apex 通常在系統上下文中執行,即當前使用者的許可權。在程式碼執行期間不會考慮欄位級安全性以及共享規則。只有匿名程式碼塊以執行程式碼的使用者的許可權執行。
我們的 Apex 程式碼不應將透過安全和共享設定隱藏的敏感資料公開給使用者。因此,Apex 安全性和強制執行共享規則至關重要。
使用 With Sharing 關鍵字
如果您使用此關鍵字,則 Apex 程式碼將對當前使用者對 Apex 程式碼的共享設定進行強制。這不會強制執行配置檔案許可權,只會強制執行資料級共享設定。
讓我們考慮一個示例,其中我們的使用者可以訪問 5 條記錄,但記錄總數為 10。因此,當 Apex 類使用“With Sharing”關鍵字宣告時,它將只返回使用者可以訪問的 5 條記錄。
示例
首先,確保您已在 Customer 物件中建立了至少 10 條記錄,其中 5 條記錄的“名稱”為“ABC 客戶”,其餘 5 條記錄為“XYZ 客戶”。然後,建立一個共享規則,將“ABC 客戶”與所有使用者共享。我們還需要確保已將 Customer 物件的 OWD 設定為私有。
將下面給出的程式碼貼上到開發者控制檯中的匿名程式碼塊中。
// Class With Sharing public with sharing class MyClassWithSharing { // Query To fetch 10 records List<apex_customer__c> CustomerList = [SELECT id, Name FROM APEX_Customer__c LIMIT 10]; public Integer executeQuery () { System.debug('List will have only 5 records and the actual records are' + CustomerList.size()+' as user has access to'+CustomerList); Integer ListSize = CustomerList.size(); return ListSize; } } // Save the above class and then execute as below // Execute class using the object of class MyClassWithSharing obj = new MyClassWithSharing(); Integer ListSize = obj.executeQuery();
不使用 With Sharing 關鍵字
顧名思義,使用此關鍵字宣告的類在系統模式下執行,即,無論使用者是否可以訪問記錄,查詢都將獲取所有記錄。
// Class Without Sharing public without sharing class MyClassWithoutSharing { List<apex_customer__c> CustomerList = [SELECT id, Name FROM APEX_Customer__c LIMIT 10]; // Query To fetch 10 records, this will return all the records public Integer executeQuery () { System.debug('List will have only 5 records and the actula records are' + CustomerList.size()+' as user has access to'+CustomerList); Integer ListSize = CustomerList.size(); return ListSize; } } // Output will be 10 records.
設定 Apex 類的安全性
您可以為特定配置檔案啟用或停用 Apex 類。以下列出了執行此操作的步驟。您可以確定哪個配置檔案應該訪問哪個類。
從類列表頁面設定 Apex 類安全性
**步驟 1** - 在“設定”中,單擊“開發”→“Apex 類”。

**步驟 2** - 單擊要限制的類的名稱。我們已單擊 CustomerOperationClass。

**步驟 3** - 單擊“安全性”。

**步驟 4** - 從“可用配置檔案”列表中選擇要啟用的配置檔案並單擊“新增”,或從“已啟用配置檔案”列表中選擇要停用的配置檔案並單擊“刪除”。

**步驟 5** - 單擊“儲存”。
從許可權集設定 Apex 安全性
**步驟 1** - 在“設定”中,單擊“管理使用者”→“許可權集”。

**步驟 2** - 選擇一個許可權集。

**步驟 3** - 單擊“Apex 類訪問”。

**步驟 4** - 單擊“編輯”。

**步驟 5** - 從“可用 Apex 類”列表中選擇要啟用的 Apex 類並單擊“新增”,或從“已啟用 Apex 類”列表中選擇要停用的 Apex 類並單擊“刪除”。

**步驟 6** - 單擊“儲存”按鈕。
Apex - 呼叫
Apex 呼叫是指執行 Apex 類的過程。只有透過以下列出的方式之一呼叫 Apex 類時,才能執行 Apex 類:
觸發器和匿名程式碼塊
為指定事件呼叫的觸發器
非同步 Apex
計劃 Apex 類以指定的時間間隔執行,或執行批處理作業
Web 服務類
Apex 電子郵件服務類
Apex Web 服務,允許透過 SOAP 和 REST Web 服務公開您的方法
Visualforce 控制器
Apex 電子郵件服務來處理傳入的電子郵件
使用 JavaScript 呼叫 Apex
Ajax 工具包來呼叫在 Apex 中實現的 Web 服務方法
我們現在將瞭解一些常見的 Apex 呼叫方法。
從執行匿名程式碼塊
您可以透過在開發者控制檯中執行匿名程式碼來呼叫 Apex 類,如下所示:
**步驟 1** - 開啟開發者控制檯。
**步驟 2** - 單擊“除錯”。

**步驟 3** - 將開啟匿名執行視窗,如下所示。現在,單擊“執行”按鈕:

**步驟 4** - 開啟除錯日誌,它將出現在“日誌”窗格中。

從觸發器
您也可以從觸發器呼叫 Apex 類。當發生指定事件時,將呼叫觸發器,並且觸發器可以在執行時呼叫 Apex 類。
以下示例程式碼顯示了當呼叫觸發器時如何執行類。
示例
// Class which will gets called from trigger public without sharing class MyClassWithSharingTrigger { public static Integer executeQuery (List<apex_customer__c> CustomerList) { // perform some logic and operations here Integer ListSize = CustomerList.size(); return ListSize; } } // Trigger Code trigger Customer_After_Insert_Example on APEX_Customer__c (after insert) { System.debug('Trigger is Called and it will call Apex Class'); MyClassWithSharingTrigger.executeQuery(Trigger.new); // Calling Apex class and // method of an Apex class } // This example is for reference, no need to execute and will have detail look on // triggers later chapters.
從 Visualforce 頁面控制器程式碼
也可以從 Visualforce 頁面呼叫 Apex 類。我們可以指定控制器或控制器擴充套件,並呼叫指定的 Apex 類。
示例
VF 頁面程式碼

Apex 類程式碼(控制器擴充套件)

Apex - 觸發器
Apex 觸發器類似於儲存過程,在發生特定事件時執行。觸發器在記錄上發生事件之前和之後執行。
語法
trigger triggerName on ObjectName (trigger_events) { Trigger_code_block }
執行觸發器
以下是可以觸發觸發器的事件:
- 插入
- 更新
- 刪除
- 合併
- Upsert
- 撤銷刪除
觸發器示例 1
假設我們收到一個業務需求,即當客戶的“客戶狀態”欄位從“無效”更改為“有效”時,我們需要建立發票記錄。為此,我們將透過以下步驟在 APEX_Customer__c 物件上建立觸發器:
**步驟 1** - 轉到 sObject
**步驟 2** - 單擊“客戶”
**步驟 3** - 在觸發器相關列表中單擊“新建”按鈕,並新增如下所示的觸發器程式碼。
// Trigger Code trigger Customer_After_Insert on APEX_Customer__c (after update) { List InvoiceList = new List(); for (APEX_Customer__c objCustomer: Trigger.new) { if (objCustomer.APEX_Customer_Status__c == 'Active') { APEX_Invoice__c objInvoice = new APEX_Invoice__c(); objInvoice.APEX_Status__c = 'Pending'; InvoiceList.add(objInvoice); } } // DML to insert the Invoice List in SFDC insert InvoiceList; }
說明
**Trigger.new** - 這是儲存當前在觸發器上下文中記錄的上下文變數,無論是插入還是更新。在本例中,此變數包含已更新的 Customer 物件的記錄。
上下文中還有其他可用的上下文變數 - trigger.old、trigger.newMap、trigger.OldMap。
觸發器示例 2
當對客戶記錄進行更新操作時,上述觸發器將執行。假設僅當客戶狀態從“無效”更改為“有效”時才需要插入發票記錄,而不是每次都插入;為此,我們可以使用另一個上下文變數 **trigger.oldMap**,它將儲存鍵作為記錄 ID,並將值作為舊記錄值。
// Modified Trigger Code trigger Customer_After_Insert on APEX_Customer__c (after update) { List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>(); for (APEX_Customer__c objCustomer: Trigger.new) { // condition to check the old value and new value if (objCustomer.APEX_Customer_Status__c == 'Active' && trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') { APEX_Invoice__c objInvoice = new APEX_Invoice__c(); objInvoice.APEX_Status__c = 'Pending'; InvoiceList.add(objInvoice); } } // DML to insert the Invoice List in SFDC insert InvoiceList; }
說明
我們使用了 Trigger.oldMap 變數,如前所述,它是一個上下文變數,儲存正在更新的記錄的 ID 和舊值。
Apex - 觸發器設計模式
設計模式用於使我們的程式碼更有效,並避免達到控制限制。開發人員經常可以編寫低效的程式碼,這會導致物件重複例項化。這可能導致低效、效能不佳的程式碼,並可能違反控制限制。這最常發生在觸發器中,因為它們可以針對一組記錄進行操作。
我們將在本章中看到一些重要的設計模式策略。
批次觸發器設計模式
在實際業務案例中,您可能需要一次處理數千條記錄。如果您的觸發器沒有設計成處理此類情況,則它在處理記錄時可能會失敗。在實現觸發器時,需要遵循一些最佳實踐。預設情況下,所有觸發器都是批次觸發器,並且可以一次處理多條記錄。您應該始終計劃一次處理多條記錄。
考慮一個業務案例,其中您需要處理大量記錄,並且您已編寫如下所示的觸發器。這與我們之前採用的示例相同,即當客戶狀態從“無效”更改為“有效”時插入發票記錄。
// Bad Trigger Example trigger Customer_After_Insert on APEX_Customer__c (after update) { for (APEX_Customer__c objCustomer: Trigger.new) { if (objCustomer.APEX_Customer_Status__c == 'Active' && trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') { // condition to check the old value and new value APEX_Invoice__c objInvoice = new APEX_Invoice__c(); objInvoice.APEX_Status__c = 'Pending'; insert objInvoice; //DML to insert the Invoice List in SFDC } } }
您現在可以看到,DML 語句已寫入 for 迴圈塊中,這在僅處理少量記錄時有效,但是當您處理數百條記錄時,它將達到每個事務的 DML 語句限制,即 **控制限制**。我們將在後續章節中詳細介紹控制限制。
為了避免這種情況,我們必須使觸發器能夠高效地一次處理多條記錄。
以下示例將幫助您理解這一點 -
// Modified Trigger Code-Bulk Trigger trigger Customer_After_Insert on APEX_Customer__c (after update) { List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>(); for (APEX_Customer__c objCustomer: Trigger.new) { if (objCustomer.APEX_Customer_Status__c == 'Active' && trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') { //condition to check the old value and new value APEX_Invoice__c objInvoice = new APEX_Invoice__c(); objInvoice.APEX_Status__c = 'Pending'; InvoiceList.add(objInvoice);//Adding records to List } } insert InvoiceList; // DML to insert the Invoice List in SFDC, this list contains the all records // which need to be modified and will fire only one DML }
此觸發器只會觸發 1 條 DML 語句,因為它將在列表上操作,並且該列表包含所有需要修改的記錄。
透過這種方式,您可以避免 DML 語句的許可權限制。
觸發器輔助類
在觸發器中編寫整個程式碼也不是一個好習慣。因此,您應該呼叫 Apex 類並將處理從觸發器委託給 Apex 類,如下所示。觸發器輔助類是為觸發器執行所有處理的類。
讓我們再次考慮我們的發票記錄建立示例。
// Below is the Trigger without Helper class trigger Customer_After_Insert on APEX_Customer__c (after update) { List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>(); for (APEX_Customer__c objCustomer: Trigger.new) { if (objCustomer.APEX_Customer_Status__c == 'Active' && trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') { // condition to check the old value and new value APEX_Invoice__c objInvoice = new APEX_Invoice__c(); objInvoice.APEX_Status__c = 'Pending'; InvoiceList.add(objInvoice); } } insert InvoiceList; // DML to insert the Invoice List in SFDC } // Below is the trigger with helper class // Trigger with Helper Class trigger Customer_After_Insert on APEX_Customer__c (after update) { CustomerTriggerHelper.createInvoiceRecords(Trigger.new, trigger.oldMap); // Trigger calls the helper class and does not have any code in Trigger }
輔助類
public class CustomerTriggerHelper { public static void createInvoiceRecords (List<apex_customer__c> customerList, Map<id, apex_customer__c> oldMapCustomer) { List<apex_invoice__c> InvoiceList = new Listvapex_invoice__c>(); for (APEX_Customer__c objCustomer: customerList) { if (objCustomer.APEX_Customer_Status__c == 'Active' && oldMapCustomer.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') { // condition to check the old value and new value APEX_Invoice__c objInvoice = new APEX_Invoice__c(); // objInvoice.APEX_Status__c = 'Pending'; InvoiceList.add(objInvoice); } } insert InvoiceList; // DML to insert the Invoice List in SFDC } }
在此,所有處理都已委託給輔助類,當我們需要新的功能時,我們只需將程式碼新增到輔助類中,而無需修改觸發器。
每個 sObject 上的單個觸發器
始終在每個物件上建立一個觸發器。如果同一個物件上的多個觸發器達到許可權限制,可能會導致衝突和錯誤。
您可以使用上下文變數根據需要從輔助類呼叫不同的方法。考慮我們之前的示例。假設我們的 createInvoice 方法應該只在記錄更新和多個事件時呼叫。然後我們可以控制執行,如下所示 -
// Trigger with Context variable for controlling the calling flow trigger Customer_After_Insert on APEX_Customer__c (after update, after insert) { if (trigger.isAfter && trigger.isUpdate) { // This condition will check for trigger events using isAfter and isUpdate // context variable CustomerTriggerHelper.createInvoiceRecords(Trigger.new); // Trigger calls the helper class and does not have any code in Trigger // and this will be called only when trigger ids after update } } // Helper Class public class CustomerTriggerHelper { //Method To Create Invoice Records public static void createInvoiceRecords (List<apex_customer__c> customerList) { for (APEX_Customer__c objCustomer: customerList) { if (objCustomer.APEX_Customer_Status__c == 'Active' && trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') { // condition to check the old value and new value APEX_Invoice__c objInvoice = new APEX_Invoice__c(); objInvoice.APEX_Status__c = 'Pending'; InvoiceList.add(objInvoice); } } insert InvoiceList; // DML to insert the Invoice List in SFDC } }
Apex - 限制
許可權執行限制確保在 Force.com 多租戶平臺上有效地使用資源。它是 Salesforce.com 為有效處理而指定的程式碼執行限制。
什麼是許可權限制?
眾所周知,Apex 在多租戶環境中執行,即單個資源由所有客戶和組織共享。因此,有必要確保沒有人壟斷資源,因此 Salesforce.com 建立了一組限制來管理和限制程式碼執行。每當任何許可權限制被超過時,它都會丟擲錯誤並停止程式執行。
從開發人員的角度來看,務必確保我們的程式碼具有可擴充套件性並且不會觸及限制。
所有這些限制都按交易基礎應用。單個觸發器執行是一次交易。
正如我們所見,觸發器設計模式有助於避免限制錯誤。我們現在將瞭解其他重要的限制。
避免 SOQL 查詢限制
您每次交易只能發出 100 個查詢,也就是說,當您的程式碼發出超過 100 個 SOQL 查詢時,它將丟擲錯誤。
示例
此示例顯示瞭如何達到 SOQL 查詢限制 -
以下觸發器迭代客戶列表並使用字串“Ok to Pay”更新子記錄(發票)的描述。
// Helper class:Below code needs o be checked. public class CustomerTriggerHelper { public static void isAfterUpdateCall(Trigger.new) { createInvoiceRecords(trigger.new);//Method call updateCustomerDescription(trigger.new); } // Method To Create Invoice Records public static void createInvoiceRecords (List<apex_customer__c> customerList) { for (APEX_Customer__c objCustomer: customerList) { if (objCustomer.APEX_Customer_Status__c == 'Active' && trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') { // condition to check the old value and new value APEX_Invoice__c objInvoice = new APEX_Invoice__c(); objInvoice.APEX_Status__c = 'Pending'; InvoiceList.add(objInvoice); } } insert InvoiceList; // DML to insert the Invoice List in SFDC } // Method to update the invoice records public static updateCustomerDescription (List<apex_customer__c> customerList) { for (APEX_Customer__c objCust: customerList) { List<apex_customer__c> invList = [SELECT Id, Name, APEX_Description__c FROM APEX_Invoice__c WHERE APEX_Customer__c = :objCust.id]; // This query will fire for the number of records customer list has and will // hit the governor limit when records are more than 100 for (APEX_Invoice__c objInv: invList) { objInv.APEX_Description__c = 'OK To Pay'; update objInv; // Update invoice, this will also hit the governor limit for DML if large // number(150) of records are there } } } }
當呼叫“updateCustomerDescription”方法並且客戶記錄數超過 100 時,它將觸及 SOQL 限制。為避免這種情況,切勿在 For 迴圈中編寫 SOQL 查詢。在這種情況下,SOQL 查詢已在 For 迴圈中編寫。
以下是一個示例,它將展示如何避免 DML 和 SOQL 限制。我們使用了巢狀關係查詢來獲取發票記錄,並使用上下文變數trigger.newMap獲取 ID 和客戶記錄的對映。
// SOQL-Good Way to Write Query and avoid limit exception // Helper Class public class CustomerTriggerHelper { public static void isAfterUpdateCall(Trigger.new) { createInvoiceRecords(trigger.new); //Method call updateCustomerDescription(trigger.new, trigger.newMap); } // Method To Create Invoice Records public static void createInvoiceRecords (List<apex_customer__c> customerList) { for (APEX_Customer__c objCustomer: customerList) { if (objCustomer.APEX_Customer_Status__c == 'Active' && trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') { // condition to check the old value and new value APEX_Invoice__c objInvoice = new APEX_Invoice__c(); objInvoice.APEX_Status__c = 'Pending'; InvoiceList.add(objInvoice); } } insert InvoiceList; // DML to insert the Invoice List in SFDC } // Method to update the invoice records public static updateCustomerDescription (List<apex_customer__c> customerList, Map<id, apex_customer__c> newMapVariable) { List<apex_customer__c> customerListWithInvoice = [SELECT id, Name,(SELECT Id, Name, APEX_Description__c FROM APEX_Invoice__r) FROM APEX_Customer__c WHERE Id IN :newMapVariable.keySet()]; // Query will be for only one time and fetches all the records List<apex_invoice__c> invoiceToUpdate = new List<apex_invoice__c>(); for (APEX_Customer__c objCust: customerList) { for (APEX_Invoice__c objInv: invList) { objInv.APEX_Description__c = 'OK To Pay'; invoiceToUpdate.add(objInv); // Add the modified records to List } } update invoiceToUpdate; } }
DML 批次呼叫
此示例顯示了批次觸發器以及觸發器輔助類模式。您必須先儲存輔助類,然後儲存觸發器。
注意 - 將以下程式碼貼上到我們之前建立的“CustomerTriggerHelper”類中。
// Helper Class public class CustomerTriggerHelper { public static void isAfterUpdateCall(List<apex_customer__c> customerList, Map<id, apex_customer__c> mapIdToCustomers, Map<id, apex_customer__c> mapOldItToCustomers) { createInvoiceRecords(customerList, mapOldItToCustomers); //Method call updateCustomerDescription(customerList,mapIdToCustomers, mapOldItToCustomers); } // Method To Create Invoice Records public static void createInvoiceRecords (List<apex_customer__c> customerList, Map<id, apex_customer__c> mapOldItToCustomers) { List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>(); List<apex_customer__c> customerToInvoice = [SELECT id, Name FROM APEX_Customer__c LIMIT 1]; for (APEX_Customer__c objCustomer: customerList) { if (objCustomer.APEX_Customer_Status__c == 'Active' && mapOldItToCustomers.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') { //condition to check the old value and new value APEX_Invoice__c objInvoice = new APEX_Invoice__c(); objInvoice.APEX_Status__c = 'Pending'; objInvoice.APEX_Customer__c = objCustomer.id; InvoiceList.add(objInvoice); } } system.debug('InvoiceList&&&'+InvoiceList); insert InvoiceList; // DML to insert the Invoice List in SFDC. This also follows the Bulk pattern } // Method to update the invoice records public static void updateCustomerDescription (List<apex_customer__c> customerList, Map<id, apex_customer__c> newMapVariable, Map<id, apex_customer__c> oldCustomerMap) { List<apex_customer__c> customerListWithInvoice = [SELECT id, Name,(SELECT Id, Name, APEX_Description__c FROM Invoices__r) FROM APEX_Customer__c WHERE Id IN :newMapVariable.keySet()]; // Query will be for only one time and fetches all the records List<apex_invoice__c> invoiceToUpdate = new List<apex_invoice__c>(); List<apex_invoice__c> invoiceFetched = new List<apex_invoice__c>(); invoiceFetched = customerListWithInvoice[0].Invoices__r; system.debug('invoiceFetched'+invoiceFetched); system.debug('customerListWithInvoice****'+customerListWithInvoice); for (APEX_Customer__c objCust: customerList) { system.debug('objCust.Invoices__r'+objCust.Invoices__r); if (objCust.APEX_Active__c == true && oldCustomerMap.get(objCust.id).APEX_Active__c == false) { for (APEX_Invoice__c objInv: invoiceFetched) { system.debug('I am in For Loop'+objInv); objInv.APEX_Description__c = 'OK To Pay'; invoiceToUpdate.add(objInv); // Add the modified records to List } } } system.debug('Value of List ***'+invoiceToUpdate); update invoiceToUpdate; // This statement is Bulk DML which performs the DML on List and avoids // the DML Governor limit } } // Trigger Code for this class: Paste this code in 'Customer_After_Insert' // trigger on Customer Object trigger Customer_After_Insert on APEX_Customer__c (after update) { CustomerTriggerHelper.isAfterUpdateCall(Trigger.new, trigger.newMap, trigger.oldMap); // Trigger calls the helper class and does not have any code in Trigger }
其他 Salesforce 許可權限制
下表列出了重要的許可權限制。
描述 | 限制 |
---|---|
總堆大小 | 6 MB/12 MB |
發出的 DML 語句總數 | 150 |
單個 SOSL 查詢檢索的記錄總數 | 2000 |
發出的 SOSL 查詢總數 | 20 |
透過 Database.getQueryLocator 檢索的記錄總數 | 10000 |
透過 SOQL 查詢檢索的記錄總數 | 50000 |
Apex - 批處理
在本章中,我們將瞭解 Apex 中的批處理。考慮以下場景,我們將每天處理大量記錄,可能是資料清理或刪除一些未使用的記錄。
什麼是批處理 Apex?
批處理 Apex 是 Apex 程式碼的非同步執行,專為處理大量記錄而設計,並且比同步程式碼具有更大的許可權限制靈活性。
何時使用批處理 Apex?
當您想每天或在特定時間間隔處理大量記錄時,您可以使用批處理 Apex。
此外,當您希望操作非同步執行時,可以實現批處理 Apex。批處理 Apex 作為開發人員必須實現的介面公開。批處理作業可以使用 Apex 以程式設計方式在執行時呼叫。批處理 Apex 在少量記錄上操作,涵蓋您的整個記錄集並將處理分解為可管理的資料塊。
使用批處理 Apex
當我們使用批處理 Apex 時,必須實現 Salesforce 提供的介面 Database.Batchable,然後以程式設計方式呼叫該類。
您可以按照以下步驟監控該類 -
要監控或停止批處理 Apex 批處理作業的執行,請轉到設定→監控→Apex 作業或作業→Apex 作業。


Database.Batchable 介面具有以下三個需要實現的方法 -
- 開始
- 執行
- 完成
現在讓我們詳細瞭解每個方法。
開始
Start 方法是 Database.Batchable 介面的三個方法之一。
語法
global void execute(Database.BatchableContext BC, list<sobject<) {}
此方法將在批處理作業開始時呼叫,並收集批處理作業將操作的資料。
請考慮以下幾點以瞭解該方法 -
當您使用簡單查詢生成批處理作業中使用的物件範圍時,請使用Database.QueryLocator物件。在這種情況下,將繞過 SOQL 資料行限制。
當您有複雜條件要處理記錄時,請使用可迭代物件。Database.QueryLocator 確定應處理的記錄範圍。
執行
現在讓我們瞭解 Database.Batchable 介面的 Execute 方法。
語法
global void execute(Database.BatchableContext BC, list<sobject<) {}
其中,list<sObject< 由 Database.QueryLocator 方法返回。
此方法在 Start 方法之後呼叫,並執行批處理作業所需的所有處理。
完成
我們現在將討論 Database.Batchable 介面的 Finish 方法。
語法
global void finish(Database.BatchableContext BC) {}
此方法在最後呼叫,您可以執行一些完成活動,例如傳送一封包含有關批處理作業已處理記錄和狀態的資訊的電子郵件。
批處理 Apex 示例
讓我們考慮我們現有的化工公司的示例,並假設我們需要更新已標記為活動且建立日期為今天的客戶記錄的客戶狀態和客戶描述欄位。這應該每天執行,並且應向用戶傳送一封有關批處理狀態的電子郵件。將客戶狀態更新為“已處理”,並將客戶描述更新為“透過批處理作業更新”。
// Batch Job for Processing the Records global class CustomerProessingBatch implements Database.Batchable<sobject> { global String [] email = new String[] {'test@test.com'}; // Add here your email address here // Start Method global Database.Querylocator start (Database.BatchableContext BC) { return Database.getQueryLocator('Select id, Name, APEX_Customer_Status__c, APEX_Customer_Decscription__c From APEX_Customer__c WHERE createdDate = today AND APEX_Active__c = true'); // Query which will be determine the scope of Records fetching the same } // Execute method global void execute (Database.BatchableContext BC, List<sobject> scope) { List<apex_customer__c> customerList = new List<apex_customer__c>(); List<apex_customer__c> updtaedCustomerList = new List<apex_customer__c>(); // List to hold updated customer for (sObject objScope: scope) { APEX_Customer__c newObjScope = (APEX_Customer__c)objScope ; // type casting from generic sOject to APEX_Customer__c newObjScope.APEX_Customer_Decscription__c = 'Updated Via Batch Job'; newObjScope.APEX_Customer_Status__c = 'Processed'; updtaedCustomerList.add(newObjScope); // Add records to the List System.debug('Value of UpdatedCustomerList '+updtaedCustomerList); } if (updtaedCustomerList != null && updtaedCustomerList.size()>0) { // Check if List is empty or not Database.update(updtaedCustomerList); System.debug('List Size ' + updtaedCustomerList.size()); // Update the Records } } // Finish Method global void finish(Database.BatchableContext BC) { Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage(); // Below code will fetch the job Id AsyncApexJob a = [Select a.TotalJobItems, a.Status, a.NumberOfErrors, a.JobType, a.JobItemsProcessed, a.ExtendedStatus, a.CreatedById, a.CompletedDate From AsyncApexJob a WHERE id = :BC.getJobId()]; // get the job Id System.debug('$$$ Jobid is'+BC.getJobId()); // below code will send an email to User about the status mail.setToAddresses(email); mail.setReplyTo('test@test.com'); // Add here your email address mail.setSenderDisplayName('Apex Batch Processing Module'); mail.setSubject('Batch Processing '+a.Status); mail.setPlainTextBody('The Batch Apex job processed' + a.TotalJobItems+'batches with '+a.NumberOfErrors+'failures'+'Job Item processed are'+a.JobItemsProcessed); Messaging.sendEmail(new Messaging.Singleemailmessage [] {mail}); } }
要執行此程式碼,請先儲存它,然後將以下程式碼貼上到 Execute anonymous 中。這將建立類的物件,並且 Database.execute 方法將執行批處理作業。作業完成後,將向指定的電子郵件地址傳送電子郵件。確保您有一個客戶記錄,其中Active已選中。
// Paste in Developer Console CustomerProessingBatch objClass = new CustomerProessingBatch(); Database.executeBatch (objClass);
執行此類後,檢查您提供的電子郵件地址,您將在其中收到包含資訊的電子郵件。此外,您可以透過監控頁面和上述步驟檢查批處理作業的狀態。
如果您檢查除錯日誌,則可以找到指示已處理多少條記錄的列表大小。
限制
我們一次最多隻能有 5 個批處理作業正在處理。這是批處理 Apex 的限制之一。
使用 Apex 詳細資訊頁面計劃 Apex 批處理作業
您可以透過 Apex 詳細資訊頁面計劃 Apex 類,如下所示 -
步驟 1 - 轉到設定⇒Apex 類,單擊 Apex 類。

步驟 2 - 單擊計劃 Apex 按鈕。

步驟 3 - 提供詳細資訊。

使用 Schedulable 介面計劃 Apex 批處理作業
您可以使用 Schedulable 介面計劃 Apex 批處理作業,如下所示 -
// Batch Job for Processing the Records global class CustomerProessingBatch implements Database.Batchable<sobject> { global String [] email = new String[] {'test@test.com'}; // Add here your email address here // Start Method global Database.Querylocator start (Database.BatchableContext BC) { return Database.getQueryLocator('Select id, Name, APEX_Customer_Status__c, APEX_Customer_Decscription__c From APEX_Customer__c WHERE createdDate = today AND APEX_Active__c = true'); // Query which will be determine the scope of Records fetching the same } // Execute method global void execute (Database.BatchableContext BC, List<sobject> scope) { List<apex_customer__c> customerList = new List<apex_customer__c>(); List<apex_customer__c> updtaedCustomerList = new List<apex_customer__c>();//List to hold updated customer for (sObject objScope: scope) { APEX_Customer__c newObjScope = (APEX_Customer__c)objScope ;//type casting from generic sOject to APEX_Customer__c newObjScope.APEX_Customer_Decscription__c = 'Updated Via Batch Job'; newObjScope.APEX_Customer_Status__c = 'Processed'; updtaedCustomerList.add(newObjScope);//Add records to the List System.debug('Value of UpdatedCustomerList '+updtaedCustomerList); } if (updtaedCustomerList != null && updtaedCustomerList.size()>0) { // Check if List is empty or not Database.update(updtaedCustomerList); System.debug('List Size' + updtaedCustomerList.size()); // Update the Records } } // Finish Method global void finish(Database.BatchableContext BC) { Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage(); // Below code will fetch the job Id AsyncApexJob a = [Select a.TotalJobItems, a.Status, a.NumberOfErrors, a.JobType, a.JobItemsProcessed, a.ExtendedStatus, a.CreatedById, a.CompletedDate From AsyncApexJob a WHERE id = :BC.getJobId()];//get the job Id System.debug('$$$ Jobid is'+BC.getJobId()); // below code will send an email to User about the status mail.setToAddresses(email); mail.setReplyTo('test@test.com');//Add here your email address mail.setSenderDisplayName('Apex Batch Processing Module'); mail.setSubject('Batch Processing '+a.Status); mail.setPlainTextBody('The Batch Apex job processed' + a.TotalJobItems+'batches with '+a.NumberOfErrors+'failures'+'Job Item processed are'+a.JobItemsProcessed); Messaging.sendEmail(new Messaging.Singleemailmessage [] {mail}); } // Scheduler Method to scedule the class global void execute(SchedulableContext sc) { CustomerProessingBatch conInstance = new CustomerProessingBatch(); database.executebatch(conInstance,100); } } // Paste in Developer Console CustomerProessingBatch objClass = new CustomerProcessingBatch(); Database.executeBatch (objClass);
Apex - 除錯
除錯是任何程式設計開發的重要組成部分。在 Apex 中,我們有一些可用於除錯的工具。其中之一是 system.debug() 方法,它在除錯日誌中列印變數的值和輸出。
我們可以使用以下兩種工具進行除錯 -
- 開發者控制檯
- 除錯日誌
透過開發者控制檯進行除錯
您可以使用開發者控制檯並執行匿名功能來除錯 Apex,如下所示 -
示例
考慮我們現有的獲取今天建立的客戶記錄的示例。我們只想瞭解查詢是否返回結果,如果是,我們將檢查列表的值。
將下面給出的程式碼貼上到 Execute anonymous 視窗中,並按照我們開啟 Execute anonymous 視窗所執行的步驟操作。
步驟 1 - 開啟開發者控制檯
步驟 2 - 從“除錯”中開啟 Execute anonymous,如下所示。

步驟 3 - 開啟 Execute Anonymous 視窗,貼上以下程式碼並單擊執行。

// Debugging The Apex List<apex_customer__c> customerList = new List<apex_customer__c>(); customerList = [SELECT Id, Name FROM APEX_Customer__c WHERE CreatedDate = today]; // Our Query System.debug('Records on List are '+customerList+' And Records are '+customerList); // Debug statement to check the value of List and Size
步驟 4 - 開啟日誌,如下所示。

步驟 5 - 在過濾器條件中輸入“USER”,如下所示。
步驟 6 - 開啟 USER DEBUG 語句,如下所示。
透過除錯日誌進行除錯
您也可以透過除錯日誌除錯相同的類。假設,您在 Customer 物件中有一個觸發器,並且需要針對某些變數值進行除錯,那麼您可以透過除錯日誌執行此操作,如下所示 -
這是更新 Description 欄位(如果修改的客戶處於活動狀態)的觸發器程式碼,並且您想檢查當前作用域中變數和記錄的值 -
trigger CustomerTrigger on APEX_Customer__c (before update) { List<apex_customer__c> customerList = new List<apex_customer__c>(); for (APEX_Customer__c objCust: Trigger.new) { System.debug('objCust current value is'+objCust); if (objCust.APEX_Active__c == true) { objCust.APEX_Customer_Description__c = 'updated'; System.debug('The record which has satisfied the condition '+objCust); } } }
按照以下步驟生成除錯日誌。
步驟 1 - 設定使用者的除錯日誌。轉到設定,在搜尋設定視窗中輸入“除錯日誌”,然後單擊連結。

步驟 2 - 設定除錯日誌,如下所示。


步驟 3 - 輸入需要設定的使用者名稱稱。在此處輸入您的姓名。

步驟 4 - 修改客戶記錄,因為事件應該發生以生成除錯日誌。

步驟 5 - 現在再次轉到除錯日誌部分。開啟除錯日誌並單擊重置。

步驟 6 - 單擊第一個除錯日誌的檢視連結。

步驟 7 - 使用瀏覽器搜尋,搜尋字串“USER”,如下所示。

除錯語句將顯示我們在其中設定斷點的欄位的值。
Apex - 測試
測試是 Apex 或任何其他應用程式開發的整合部分。在 Apex 中,我們有單獨的測試類來開發所有單元測試。
測試類
在 SFDC 中,程式碼必須具有 75% 的程式碼覆蓋率才能部署到生產環境。此程式碼覆蓋率由測試類執行。測試類是測試其他 Apex 類功能的程式碼片段。
讓我們為我們之前編寫的其中一個程式碼編寫一個測試類。我們將編寫測試類來覆蓋我們的觸發器和輔助類程式碼。以下是需要覆蓋的觸發器和輔助類。
// Trigger with Helper Class trigger Customer_After_Insert on APEX_Customer__c (after update) { CustomerTriggerHelper.createInvoiceRecords(Trigger.new, trigger.oldMap); //Trigger calls the helper class and does not have any code in Trigger } // Helper Class: public class CustomerTriggerHelper { public static void createInvoiceRecords (List<apex_customer__c> customerList, Map<id, apex_customer__c> oldMapCustomer) { List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>(); for (APEX_Customer__c objCustomer: customerList) { if (objCustomer.APEX_Customer_Status__c == 'Active' && oldMapCustomer.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') { // condition to check the old value and new value APEX_Invoice__c objInvoice = new APEX_Invoice__c(); objInvoice.APEX_Status__c = 'Pending'; objInvoice.APEX_Customer__c = objCustomer.id; InvoiceList.add(objInvoice); } } insert InvoiceList; // DML to insert the Invoice List in SFDC } }
建立測試類
在本節中,我們將瞭解如何建立測試類。
資料建立
我們需要在測試類本身中為測試類建立資料。測試類預設情況下無法訪問組織資料,但如果您設定 @isTest(seeAllData = true),則它也將能夠訪問組織的資料。
@isTest 註解
使用此註解,您宣告這是一個測試類,並且它不會計入組織的程式碼總數限制。
testMethod 關鍵字
單元測試方法是不接受引數、不向資料庫提交資料、不傳送電子郵件,並且在方法定義中使用 testMethod 關鍵字或 isTest 註解宣告的方法。此外,測試方法必須定義在測試類中,即使用 isTest 註解的類。
在我們的示例中,我們使用了 'myUnitTest' 測試方法。
Test.startTest() 和 Test.stopTest()
這些是測試類可用的標準測試方法。這些方法包含我們將模擬測試的事件或操作。例如,在這個示例中,我們將測試我們的觸發器和輔助類,以透過更新記錄來模擬觸發器觸發,就像我們在啟動和停止塊中所做的那樣。這還為啟動和停止塊中的程式碼提供了單獨的許可權限制。
System.assert()
此方法檢查期望輸出與實際輸出是否一致。在這種情況下,我們期望插入一個發票記錄,因此我們添加了斷言來檢查這一點。
示例
/** * This class contains unit tests for validating the behavior of Apex classes * and triggers. * * Unit tests are class methods that verify whether a particular piece * of code is working properly. Unit test methods take no arguments, * commit no data to the database, and are flagged with the testMethod * keyword in the method definition. * * All test methods in an organization are executed whenever Apex code is deployed * to a production organization to confirm correctness, ensure code * coverage, and prevent regressions. All Apex classes are * required to have at least 75% code coverage in order to be deployed * to a production organization. In addition, all triggers must have some code coverage. * * The @isTest class annotation indicates this class only contains test * methods. Classes defined with the @isTest annotation do not count against * the organization size limit for all Apex scripts. * * See the Apex Language Reference for more information about Testing and Code Coverage. */ @isTest private class CustomerTriggerTestClass { static testMethod void myUnitTest() { //Create Data for Customer Objet APEX_Customer__c objCust = new APEX_Customer__c(); objCust.Name = 'Test Customer'; objCust.APEX_Customer_Status__c = 'Inactive'; insert objCust; // Now, our trigger will fire on After update event so update the Records Test.startTest(); // Starts the scope of test objCust.APEX_Customer_Status__c = 'Active'; update objCust; Test.stopTest(); // Ends the scope of test // Now check if it is giving desired results using system.assert // Statement.New invoice should be created List<apex_invoice__c> invList = [SELECT Id, APEX_Customer__c FROM APEX_Invoice__c WHERE APEX_Customer__c = :objCust.id]; system.assertEquals(1,invList.size()); // Check if one record is created in Invoivce sObject } }
執行測試類
按照以下步驟執行測試類:
步驟 1 - 轉到 Apex 類 ⇒ 點選類名稱 'CustomerTriggerTestClass'。
步驟 2 - 點選“執行測試”按鈕,如圖所示。

步驟 3 - 檢查狀態

步驟 4 - 現在檢查我們為其編寫測試的類和觸發器
類

觸發器

我們的測試已成功完成。
Apex - 部署
什麼是 SFDC 中的部署?
到目前為止,我們已在開發人員版本中開發了程式碼,但在現實場景中,您需要在沙盒中進行此開發,然後您可能需要將其部署到另一個沙盒或生產環境,這稱為部署。簡而言之,這是元資料從一個組織到另一個組織的移動。這樣做的原因是您無法在 Salesforce 生產組織中開發 Apex。當您在開發時,即時使用者訪問系統可能會導致資料不穩定或應用程式損壞。

可用於部署的工具:
- Force.com IDE
- 更改集
- SOAP API
- Force.com 遷移工具
由於我們使用開發人員版本進行開發和學習,因此我們無法使用需要 SFDC 企業版或其他付費版本的更改集或其他工具。因此,在本教程中,我們將詳細說明 Force.com IDE 部署方法。
Force.com Eclipse IDE
步驟 1 - 開啟 Eclipse 並開啟需要部署的類觸發器。

步驟 2 - 單擊“部署到伺服器”後,輸入需要部署元件的組織的使用者名稱和密碼。

透過執行上述步驟,您的 Apex 元件將部署到目標組織。
使用更改集進行部署
您可以透過連線組織來透過部署設定將驗證規則、工作流規則、Apex 類和觸發器從一個組織部署到另一個組織。在這種情況下,必須連線組織。
要開啟部署設定,請按照以下步驟操作。請記住,開發人員版本中不提供此功能:
步驟 1 - 轉到設定並搜尋“部署”。
步驟 2 - 點選“出站更改集”以建立要部署的更改集。
步驟 3 - 使用“新增”按鈕將元件新增到更改集,然後儲存並點選“上傳”。
步驟 4 - 轉到目標組織,點選入站更改集,最後點選“部署”。
部署的 SOAP API 呼叫
我們只對這種方法進行簡要概述,因為它不是常用方法。
您可以使用以下方法呼叫來部署您的元資料。
- compileAndTest()
- compileClasses()
- compileTriggers()
Force.com 遷移工具
此工具用於指令碼部署。您必須下載 Force.com 遷移工具,然後才能執行基於檔案的部署。您可以下載 Force.com 遷移工具,然後進行指令碼部署。