บทแนะนำการใช้งาน Salesforce Apex สำหรับผู้เริ่มต้น
⚡ สรุปอย่างชาญฉลาด
การเขียนโปรแกรม Apex ช่วยให้นักพัฒนา Salesforce มีภาษาเชิงวัตถุที่มีการกำหนดประเภทข้อมูลอย่างเข้มงวดสำหรับการเพิ่มตรรกะทางธุรกิจที่กำหนดเองลงใน CRM โดยรองรับคลาส ทริกเกอร์ และงานแบบแบตช์ ในขณะที่ข้อจำกัดของ Governor Limits ช่วยรักษาเสถียรภาพของแพลตฟอร์มแบบหลายผู้เช่าที่ใช้ร่วมกัน

Apex ใน Salesforce คืออะไร?
ปลาย Apex เป็นภาษาโปรแกรมเชิงวัตถุและมีการกำหนดประเภทข้อมูลอย่างเข้มงวด พัฒนาโดย Salesforce สำหรับการสร้างแอปพลิเคชันซอฟต์แวร์เป็นบริการ (SaaS) และการจัดการความสัมพันธ์กับลูกค้า (CRM) Apex ช่วยให้นักพัฒนาสามารถสร้างแอปพลิเคชัน SaaS ของบุคคลที่สามและเพิ่มตรรกะทางธุรกิจให้กับเหตุการณ์ของระบบโดยการให้การสนับสนุนฐานข้อมูลแบ็กเอนด์และอินเทอร์เฟซไคลเอ็นต์-เซิร์ฟเวอร์
Apex ช่วยให้นักพัฒนาสามารถเพิ่มตรรกะทางธุรกิจให้กับเหตุการณ์ของระบบ เช่น การคลิกปุ่ม การอัปเดตเรคอร์ดที่เกี่ยวข้อง และหน้า Visualforce Apex มีไวยากรณ์ที่คล้ายกับ Java. ลงทะเบียนสำหรับ Salesforce เพื่อเรียนรู้วิธีการทำงานของระบบ CRM
คุณสมบัติของภาษาโปรแกรมเอเพ็กซ์
นี่คือคุณสมบัติที่สำคัญของ Salesforce Apex:
- Apex เป็นภาษาที่ไม่คำนึงถึงตัวพิมพ์ใหญ่เล็ก
- คุณสามารถดำเนินการ DML เช่น INSERT, UPDATE, UPSERT และ DELETE กับเรคอร์ด sObject โดยใช้ Apex ได้
- คุณสามารถค้นหาข้อมูลในเรคอร์ด sObject โดยใช้ SOQL (Salesforce Object Query Language) และ SOSL (Salesforce Object Search Language) ใน Apex ได้
- ช่วยให้คุณสร้าง การทดสอบหน่วย และดำเนินการเพื่อตรวจสอบ ความครอบคลุมของรหัส และประสิทธิภาพของโค้ดใน Apex
- Apex ดำเนินการในสภาพแวดล้อมที่มีผู้เช่าหลายรายและ Salesforce Salesforce ได้กำหนดขีดจำกัดของผู้ว่าการ (governor limits) เพื่อป้องกันไม่ให้ผู้ใช้ผูกขาดทรัพยากรที่ใช้ร่วมกัน โค้ดใดๆ ที่ละเมิดขีดจำกัดของผู้ว่าการของ Salesforce จะล้มเหลวและแสดงข้อผิดพลาดขึ้น
- อ็อบเจ็กต์ของ Salesforce สามารถใช้เป็นชนิดข้อมูลใน Apex ได้ ตัวอย่างเช่น:
Account acc = new Account();
ในที่นี้ Account คืออ็อบเจ็กต์มาตรฐานของ Salesforce
- Apex จะอัปเกรดโดยอัตโนมัติทุกครั้งที่มีการเปิดตัว Salesforce
นักพัฒนาควรเลือกใช้ Apex เมื่อใด?
ควรเขียนโค้ด Apex ก็ต่อเมื่อสถานการณ์ทางธุรกิจมีความซับซ้อนเกินกว่าจะนำไปใช้ได้โดยใช้ฟังก์ชันสำเร็จรูปที่ใช้งานง่ายของ Salesforce เท่านั้น
ต่อไปนี้เป็นสถานการณ์บางส่วนที่คุณจำเป็นต้องเขียนโค้ด Apex:
- เพื่อสร้างบริการเว็บที่รวม Salesforce เข้ากับแอปพลิเคชันอื่น ๆ
- เพื่อใช้งานการตรวจสอบความถูกต้องแบบกำหนดเองกับ sObjects
- เพื่อเรียกใช้ตรรกะ Apex แบบกำหนดเองเมื่อมีการดำเนินการ DML
- เพื่อนำฟังก์ชันการทำงานที่ไม่สามารถสร้างได้ด้วยเครื่องมืออัตโนมัติแบบประกาศที่มีอยู่ เช่น Flow มาใช้
- เพื่อติดตั้ง บริการอีเมล ซึ่งประมวลผลเนื้อหา ส่วนหัว และไฟล์แนบของอีเมลขาเข้า
เมื่อคุณรู้แล้วว่า Apex เป็นตัวเลือกที่เหมาะสมเมื่อใด ขั้นตอนต่อไปคือการทำความเข้าใจว่าเกิดอะไรขึ้นกับโค้ดของคุณหลังจากที่คุณบันทึกแล้ว
โครงสร้างการทำงานของ Apex
ลำดับขั้นตอนการทำงานของโค้ด Apex มีดังนี้:
- การดำเนินการของนักพัฒนา: เมื่อนักพัฒนาบันทึกโค้ดลงในแพลตฟอร์ม โค้ด Apex ทั้งหมดจะถูกคอมไพล์เป็นชุดคำสั่งที่ตัวแปลภาษา Apex runtime สามารถเข้าใจได้ จากนั้นคำสั่งเหล่านี้จะถูกบันทึกเป็นเมตาเดต้าบนแพลตฟอร์ม
- การดำเนินการของผู้ใช้ปลายทาง: เมื่อเหตุการณ์ของผู้ใช้เรียกใช้โค้ด Apex เซิร์ฟเวอร์แพลตฟอร์มจะดึงคำสั่งที่คอมไพล์แล้วจากเมตาเดตาและประมวลผลผ่านตัวแปล Apex ก่อนที่จะส่งผลลัพธ์กลับคืน
แผนภาพด้านล่างแสดงให้เห็นว่าการกระทำของนักพัฒนาและผู้ใช้ปลายทางมีปฏิสัมพันธ์กับเซิร์ฟเวอร์แอปพลิเคชัน Lightning Platform อย่างไร:
สภาพแวดล้อมการพัฒนาเอเพ็กซ์
โค้ด Apex สามารถพัฒนาได้ทั้งในสภาพแวดล้อมทดสอบ (sandbox) หรือในองค์กร Developer Edition ของ Salesforce
แนวทางปฏิบัติที่ดีที่สุดคือการพัฒนาโค้ดในสภาพแวดล้อมทดสอบ (sandbox) ก่อน แล้วจึงนำไปใช้งานจริงในสภาพแวดล้อมการผลิต ดังตัวอย่างด้านล่าง:
เครื่องมือพัฒนาโค้ด Apex: ต่อไปนี้คือเครื่องมือสามอย่างที่ใช้ในการพัฒนาโค้ด Apex ใน Salesforce ทุกเวอร์ชัน:
- คอนโซลนักพัฒนาซอฟต์แวร์
- Visual Studio Code พร้อมด้วย Salesforce Extension Pack (ซึ่งมาแทนที่ Force.com IDE ที่เลิกใช้งานไปแล้ว)
- Code ตัวแก้ไขในส่วนติดต่อผู้ใช้การตั้งค่า Salesforce
เมื่อสภาพแวดล้อมของคุณพร้อมแล้ว เรามาดูส่วนประกอบพื้นฐานของภาษากัน โดยเริ่มจากชนิดข้อมูล
ประเภทข้อมูลใน Apex
ต่อไปนี้คือประเภทข้อมูลที่ Apex รองรับ:
ดั้งเดิม
จำนวนเต็ม DoubleLong, Date, Datetime, Decimal, Time, Blob, String, ID และ Boolean ถือเป็นชนิดข้อมูลพื้นฐาน ชนิดข้อมูลพื้นฐานทั้งหมดจะถูกส่งผ่านโดยค่า ไม่ใช่โดยการอ้างอิง
คอลเลคชั่น
ใน Apex มีคอลเลกชันให้เลือกใช้ 3 ประเภท:
- รายการ: เป็นชุดของข้อมูลพื้นฐาน, sObjects, คอลเลกชัน หรืออ็อบเจ็กต์ Apex ที่เรียงลำดับตามดัชนี
- ตั้ง: กลุ่มขององค์ประกอบที่ไม่ซ้ำกัน โดยไม่มีลำดับ
- แผนที่: เป็นชุดของคีย์ที่ไม่ซ้ำกันซึ่งแมปกับค่าเดียว ซึ่งอาจเป็นประเภทข้อมูลพื้นฐาน, sObjects, คอลเลกชัน หรืออ็อบเจ็กต์ Apex ก็ได้
วัตถุ
นี่เป็นประเภทข้อมูลพิเศษใน Salesforce มันคล้ายกับตารางใน SQL และมีฟิลด์ที่คล้ายกับคอลัมน์ใน SQL
เอนัมส์
Enum คือค่าสัมบูรณ์tracชนิดข้อมูล t ที่เก็บค่าหนึ่งค่าจากชุดตัวระบุที่กำหนดไว้จำนวนจำกัด
คลาส อ็อบเจ็กต์ และอินเทอร์เฟซ
คลาสและอินเทอร์เฟซ Apex ที่ผู้ใช้กำหนดเองสามารถใช้เป็นชนิดข้อมูลได้เช่นกัน อ็อบเจ็กต์หมายถึงอินสแตนซ์ของชนิดข้อมูลใดๆ ที่ Apex รองรับ
ไวยากรณ์เอเพ็กซ์
การประกาศตัวแปร
เนื่องจาก Apex เป็นภาษาที่มีการกำหนดประเภทข้อมูลอย่างเข้มงวด การประกาศตัวแปรพร้อมระบุประเภทข้อมูลจึงเป็นสิ่งจำเป็นใน Apex
ตัวอย่างเช่น:
Contact con = new Contact();
ในที่นี้ ตัวแปร con ถูกประกาศโดยกำหนดชนิดข้อมูลเป็น Contact
แบบสอบถาม SOQL
SOQL ย่อมาจาก Salesforce Object Query Language SOQL ใช้สำหรับดึงข้อมูลเรคอร์ด sObject จากฐานข้อมูล Salesforce ตัวอย่างเช่น:
Account acc = [SELECT Id, Name FROM Account LIMIT 1];
คำสั่งค้นหาข้างต้นดึงข้อมูลบัญชีจากฐานข้อมูล Salesforce
คำสั่งวนรอบ
คำสั่งลูปใช้สำหรับวนซ้ำข้อมูลในลิสต์ โดยจำนวนครั้งในการวนซ้ำจะเท่ากับจำนวนข้อมูลในลิสต์ ตัวอย่างเช่น:
List<Account> listOfAccounts = [SELECT Id, Name FROM Account LIMIT 100];
// iteration over the list of accounts
for(Account acc : listOfAccounts){
//your logic
}
ในโค้ดตัวอย่างข้างต้น listOfAccounts เป็นตัวแปรชนิดข้อมูล List
คำชี้แจงการควบคุมการไหล
คำสั่งควบคุมการไหลของโปรแกรมมีประโยชน์เมื่อคุณต้องการเรียกใช้โค้ดบางบรรทัดตามเงื่อนไขที่กำหนดไว้
ตัวอย่างเช่น:
List<Account> listOfAccounts = [SELECT Id, Name FROM Account LIMIT 100];
// execute the logic if the size of the account list is greater than zero
if(listOfAccounts.size() > 0){
//your logic
}
โค้ดส่วนด้านบนนี้ใช้สำหรับเรียกดูข้อมูลบัญชีจากฐานข้อมูลและตรวจสอบขนาดของรายการ
คำแถลง DML
DML ย่อมาจาก Data Manipulation Language คำสั่ง DML ใช้สำหรับจัดการข้อมูลในฐานข้อมูลของ Salesforce ตัวอย่างเช่น:
Account acc = new Account(Name = 'Test Account'); insert acc; //DML statement to create account record.
ตัวระบุการเข้าถึง Apex
ต่อไปนี้คือตัวระบุการเข้าถึงที่ Apex รองรับ:
สาธารณะ
ตัวระบุการเข้าถึงนี้ให้สิทธิ์ในการเข้าถึงคลาส เมธอด หรือตัวแปรที่จะใช้โดย Apex ภายในเนมสเปซ
Private
ตัวระบุการเข้าถึงนี้อนุญาตให้เข้าถึงคลาส เมธอด หรือตัวแปรเพื่อใช้งานเฉพาะที่ หรือภายในส่วนของโค้ดที่กำหนดไว้ เมธอดและตัวแปรทั้งหมดที่ไม่ได้กำหนดตัวระบุการเข้าถึงไว้ จะใช้ตัวระบุการเข้าถึงเริ่มต้นคือ private
มีการป้องกัน
ตัวระบุการเข้าถึงนี้อนุญาตให้คลาสภายในใดๆ ก็ตามที่อยู่ในคลาส Apex ที่กำหนดไว้ สามารถเข้าถึงเมธอดหรือตัวแปรได้
เหตุการณ์ที่
ตัวระบุการเข้าถึงนี้อนุญาตให้เข้าถึงคลาส เมธอด หรือตัวแปรที่ Apex สามารถใช้งานได้ทั้งภายในและภายนอกเนมสเปซ แนวทางปฏิบัติที่ดีที่สุดคือการไม่ใช้คำหลัก global เว้นแต่จำเป็นจริงๆ
คีย์เวิร์ดใน Apex
ด้วยการแชร์
หากมีการกำหนดคลาสด้วยคีย์เวิร์ดนี้ กฎการแชร์ทั้งหมดที่ใช้กับผู้ใช้ปัจจุบันจะถูกบังคับใช้ หากไม่มีคีย์เวิร์ดนี้ โค้ดจะทำงานภายใต้บริบทของระบบ
ตัวอย่างเช่น:
public with sharing class MyApexClass{
// sharing rules enforced when code in this class executes
}
โดยไม่ต้องแบ่งปัน
หากมีการกำหนดคลาสโดยใช้คีย์เวิร์ดนี้ กฎการแชร์ที่ใช้กับผู้ใช้ปัจจุบันจะไม่ถูกบังคับใช้
ตัวอย่างเช่น:
public without sharing class MyApexClass{
// sharing rules are not enforced when code in this class executes
}
คงที่
ตัวแปรหรือเมธอดที่กำหนดด้วยคีย์เวิร์ด static จะถูกกำหนดค่าเริ่มต้นเพียงครั้งเดียวและเชื่อมโยงกับคลาส ตัวแปรและเมธอด static สามารถเรียกใช้ได้โดยตรงจากชื่อคลาสโดยไม่ต้องสร้างอินสแตนซ์ของคลาส
สุดท้าย
ค่าคงที่หรือเมธอดที่กำหนดด้วยคีย์เวิร์ด final ไม่สามารถถูกเขียนทับได้ ตัวอย่างเช่น:
public class myCls {
static final Integer INT_CONST = 10;
}
หากคุณพยายามแทนที่ค่าของตัวแปร INT_CONST นี้ คุณจะได้รับข้อยกเว้น – System.FinalException: ตัวแปร Final ได้รับการกำหนดค่าเริ่มต้นไปแล้ว
บริการรถส่ง
คำหลักนี้ส่งคืนค่าจากวิธีการ ตัวอย่างเช่น:
public String getName() {
return 'Test';
}
โมฆะ
ฟังก์ชันนี้ใช้กำหนดค่าคงที่ว่างเปล่า และสามารถกำหนดให้กับตัวแปรได้ ตัวอย่างเช่น:
Boolean b = null;
เสมือน
หากคลาสถูกกำหนดด้วยคีย์เวิร์ด virtual คลาสนั้นสามารถขยายและเขียนทับได้
abstract
ถ้าคลาสถูกกำหนดด้วยค่าสัมบูรณ์tracคีย์เวิร์ด t จะต้องมีเมธอดอย่างน้อยหนึ่งเมธอดที่มีคีย์เวิร์ด abstract และวิธีการนั้นควรมีเพียงแค่ลายเซ็นเท่านั้น
ตัวอย่างเช่น:
public abstract class MyAbstractClass {
abstract Integer myAbstractMethod1();
}
สายเอเพ็กซ์
สตริงคือชุดของตัวอักษร โดยไม่มีการจำกัดจำนวนตัวอักษร ตัวอย่างเช่น:
String name = 'Test';
คลาส String ใน Salesforce มีเมธอดในตัวหลายวิธี ต่อไปนี้คือเมธอดที่ใช้บ่อยบางส่วน:
ย่อ(maxWidth)
เมธอดนี้จะตัดสตริงให้มีความยาวตามที่ระบุ และจะคืนค่าสตริงที่ตัดแล้วหากความยาวของสตริงที่ให้มามากกว่าความยาวที่ระบุ มิฉะนั้นจะคืนค่าสตริงเดิม หากค่าของตัวแปร maxWidth น้อยกว่า 4 เมธอดนี้จะโยนข้อยกเว้นขณะรันไทม์ – System.StringException: ความกว้างขั้นต่ำของการย่อคือ 4
ตัวอย่างเช่น:
String s = 'Hello World';
String s2 = s.abbreviate(8);
System.debug('s2: ' + s2); //Hello...
ใช้ตัวพิมพ์ใหญ่ ()
เมธอดนี้จะแปลงอักษรตัวแรกของสตริงเป็นตัวพิมพ์ชื่อเรื่องและส่งกลับ
ตัวอย่างเช่น:
String s = 'hello';
String s2 = s.capitalize();
System.assertEquals('Hello', s2);
มี (สตริงย่อย)
เมธอดนี้จะคืนค่า true หากสตริงที่เรียกใช้เมธอดนี้มีสตริงย่อยที่ระบุไว้
String name1 = 'test1';
String name2 = 'test';
Boolean flag = name1.contains(name2);
System.debug('flag:: ' + flag); //true
เท่ากับ (stringOrId)
เมธอดนี้จะคืนค่า true หากพารามิเตอร์ที่ส่งผ่านไม่ใช่ค่าว่างและแสดงถึงลำดับไบนารีของอักขระเดียวกันกับสตริงที่เรียกใช้เมธอดนี้
เมื่อเปรียบเทียบค่า Id ความยาวของ Id อาจไม่เท่ากัน ตัวอย่างเช่น หากสตริงที่แสดง Id ที่มีความยาว 15 ตัวอักษรถูกเปรียบเทียบกับอ็อบเจ็กต์ที่แสดง Id ที่มีความยาว 18 ตัวอักษร เมธอดนี้ก็ยังคงคืนค่าเป็นจริง ตัวอย่างเช่น:
String stringValue15 = '001D000000Ju1zH';
Id idValue18 = '001D000000Ju1zHIAR';
Boolean result = stringValue15.equals(idValue18);
System.debug('result: ' + result); //true
ในตัวอย่างข้างต้น เมธอด equals จะเปรียบเทียบ ID ของวัตถุที่มี 15 ตัวอักษรกับ ID ของวัตถุที่มี 18 ตัวอักษร และหาก ID ทั้งสองแสดงถึงลำดับไบนารีเดียวกัน เมธอดจะคืนค่า true
ใช้วิธีนี้เพื่อทำการเปรียบเทียบแบบคำนึงถึงขนาดตัวพิมพ์
หลบหนี SingleQuotes (stringToEscape)
เมธอดนี้จะเพิ่มอักขระหลีก (\) ก่อนเครื่องหมายอัญประกาศเดี่ยวใดๆ ในสตริงและส่งคืนผลลัพธ์ เมธอดนี้ป้องกันการโจมตีแบบ SOQL injection ขณะสร้างคำสั่ง SOQL แบบไดนามิก โดยจะทำให้มั่นใจได้ว่าเครื่องหมายอัญประกาศเดี่ยวทั้งหมดจะถูกมองว่าเป็นสตริงที่ล้อมรอบแทนที่จะเป็นคำสั่งฐานข้อมูล
ตัวอย่างเช่น:
String s = 'Hello \'Tom\''; String escapedStr = String.escapeSingleQuotes(s); System.debug(escapedStr); // Outputs Hello \'Tom\'
ลบ (สตริงย่อย)
เมธอดนี้จะลบส่วนย่อยของสตริงที่ระบุทั้งหมดออกจากสตริงที่เรียกใช้เมธอด และส่งคืนสตริงที่ได้จากการลบ
ตัวอย่างเช่น:
String s1 = 'Salesforce and force.com';
String s2 = s1.remove('force');
System.debug('s2: ' + s2); // 'Sales and .com'
สตริงย่อย (startIndex)
เมธอดนี้จะส่งคืนสตริงย่อยที่เริ่มต้นจากอักขระที่ตำแหน่ง startIndex และขยายไปจนถึงจุดสิ้นสุดของสตริง
ตัวอย่างเช่น:
String s1 = 'hamburger';
String s2 = s1.substring(3);
System.debug('s2: ' + s2); //burger
ย้อนกลับ ()
เมธอดนี้จะสลับลำดับตัวอักษรทั้งหมดในสตริงและส่งคืนค่าเดิม ตัวอย่างเช่น:
String s = 'Hello';
String s2 = s.reverse();
System.debug('s2:::: ' + s2); // olleH
ตัดแต่ง()
เมธอดนี้จะลบช่องว่างด้านหน้าและด้านหลังของสตริงทั้งหมด แล้วส่งค่าสตริงนั้นกลับมา
มูลค่าของ (เพื่อแปลง)
เมธอดนี้จะส่งคืนสตริงที่แสดงถึงวัตถุที่ส่งเข้ามา
สตริง คลาส และคีย์เวิร์ดจะมารวมกันเมื่อคุณเริ่มจัดกลุ่มตรรกะลงในหน่วยที่สามารถนำกลับมาใช้ใหม่ได้ ซึ่งนั่นคือจุดประสงค์ของคลาสใน Apex นั่นเอง
เอเพ็กซ์คลาส
คลาสใน Apex คือแบบแผนหรือแม่แบบที่ใช้สร้างอ็อบเจ็กต์ อ็อบเจ็กต์คืออินสแตนซ์ของคลาส
มีสามวิธีในการสร้างคลาส Apex ใน Salesforce:
- คอนโซลนักพัฒนาซอฟต์แวร์
- Visual Studio Code พร้อมด้วย Salesforce Extension Pack
- หน้าแสดงรายละเอียดคลาส Apex ในการตั้งค่า
ใน Apex คุณสามารถกำหนดคลาสภายนอก หรือที่เรียกว่าคลาสระดับบนสุด และคุณยังสามารถกำหนดคลาสภายในคลาสภายนอก ซึ่งเรียกว่าคลาสภายในได้อีกด้วย
จำเป็นต้องใช้ตัวกำหนดสิทธิ์การเข้าถึง เช่น global หรือ public ในการประกาศคลาสภายนอก
ไม่จำเป็นต้องใช้ตัวแก้ไขการเข้าถึงในการประกาศคลาสภายใน
คลาสใน Apex ถูกกำหนดโดยใช้คีย์เวิร์ด `class` ตามด้วยชื่อคลาส
คีย์เวิร์ด `extends` ใช้สำหรับขยายคลาสที่มีอยู่แล้วในคลาส Apex และคีย์เวิร์ด `implements` ใช้สำหรับใช้งานอินเทอร์เฟซในคลาส Apex
Salesforce Apex ไม่รองรับการสืบทอดแบบหลายทาง กล่าวคือ คลาส Apex สามารถสืบทอดจากคลาส Apex ที่มีอยู่ได้เพียงคลาสเดียว แต่สามารถใช้งานอินเทอร์เฟซได้หลายรายการ
คลาสใน Apex สามารถมีคอนสตรัคเตอร์ที่ผู้ใช้กำหนดเองได้ และหากไม่มีคอนสตรัคเตอร์ที่ผู้ใช้กำหนดเอง ระบบจะใช้คอนสตรัคเตอร์เริ่มต้นแทน โค้ดในคอนสตรัคเตอร์จะทำงานเมื่อมีการสร้างอินสแตนซ์ของคลาส
ไวยากรณ์ของคลาส Apex:
public class myApexClass{
// variable declaration
//constructor
public myApexClass(){
}
//methods declaration
}
คีย์เวิร์ด `new` ใช้สำหรับสร้างอินสแตนซ์ของคลาส Apex ด้านล่างนี้คือไวยากรณ์สำหรับการสร้างอินสแตนซ์ของคลาส Apex:
myApexClass obj = new myApexClass();
เอเพ็กซ์เก็ตเตอร์และเซ็ตเตอร์
คุณสมบัติ Apex คล้ายกับตัวแปร Apex คุณสมบัติ Apex จำเป็นต้องมี getter และ setter ซึ่งสามารถใช้เรียกใช้โค้ดก่อนที่จะเข้าถึงหรือเปลี่ยนแปลงค่าของคุณสมบัติ โค้ดใน getter จะทำงานเมื่ออ่านค่าของคุณสมบัติ โค้ดใน setter จะทำงานเมื่อเปลี่ยนแปลงค่าของคุณสมบัติ คุณสมบัติใดๆ ที่มีเฉพาะ getter จะถือว่าเป็นแบบอ่านอย่างเดียว คุณสมบัติใดๆ ที่มีเฉพาะ setter จะถือว่าเป็นแบบเขียนอย่างเดียว และคุณสมบัติใดๆ ที่มีทั้ง getter และ setter จะถือว่าเป็นแบบอ่านและเขียน ไวยากรณ์ของคุณสมบัติ Apex:
public class myApexClass {
// Property declaration
access_modifier return_type property_name {
get {
//code
}
set{
//code
}
}
}
ในที่นี้ access_modifier คือตัวแก้ไขการเข้าถึงของพร็อพเพอร์ตี้, return_type คือชนิดข้อมูลของพร็อพเพอร์ตี้ และ property_name คือชื่อของพร็อพเพอร์ตี้
ด้านล่างนี้คือตัวอย่างของพร็อพเพอร์ตี้ใน Apex ที่มีทั้งตัวเข้าถึงแบบ get และ set:
public class myApex{
public String name{
get{ return name; }
set{ name = value; }
}
}
ในที่นี้ ชื่อของพร็อพเพอร์ตี้คือ name ซึ่งเป็นพร็อพเพอร์ตี้สาธารณะ และส่งคืนค่าประเภท String
ไม่จำเป็นต้องใส่โค้ดในบล็อก get และ set สามารถเว้นบล็อกเหล่านี้ว่างไว้เพื่อกำหนดคุณสมบัติอัตโนมัติได้ ตัวอย่างเช่น:
public double MyReadWriteProp{ get; set; }
ตัวเข้าถึงแบบ get และ set สามารถกำหนดได้โดยใช้ตัวดัดแปลงการเข้าถึงของตนเอง หากตัวเข้าถึงถูกกำหนดด้วยตัวดัดแปลง ตัวดัดแปลงนั้นจะแทนที่ตัวดัดแปลงการเข้าถึงของคุณสมบัติ ตัวอย่างเช่น:
public String name{private get; set;}// name is private for read and public for write.
คลาสจะกำหนดตรรกะที่นำกลับมาใช้ซ้ำได้ ซึ่งคุณจะเรียกใช้โดยตรง ทริกเกอร์ ซึ่งจะกล่าวถึงในหัวข้อถัดไป จะทำงานโดยอัตโนมัติทุกครั้งที่มีการเปลี่ยนแปลงข้อมูล
เอเพ็กซ์ทริกเกอร์
ทริกเกอร์ของ Apex ช่วยให้คุณสามารถเรียกใช้คำสั่ง Apex แบบกำหนดเองก่อนและหลังการดำเนินการ DML ได้
Apex รองรับทริกเกอร์สองประเภทต่อไปนี้:
ก่อนการกระตุ้น: ทริกเกอร์เหล่านี้ใช้สำหรับตรวจสอบและอัปเดตค่าของฟิลด์ก่อนที่จะบันทึกข้อมูลลงในฐานข้อมูล
หลังจากเกิดเหตุการณ์กระตุ้น: ทริกเกอร์เหล่านี้ใช้เพื่อเข้าถึงค่าฟิลด์ (เช่น รหัสระเบียนและฟิลด์ LastModifiedDate) ที่ระบบตั้งค่าหลังจากบันทึกระเบียนลงในฐานข้อมูลแล้ว ค่าฟิลด์เหล่านี้สามารถใช้เพื่อแก้ไขระเบียนอื่นๆ ได้ ระเบียนที่ทำงานหลังจากทริกเกอร์ทำงานจะเป็นแบบอ่านอย่างเดียว
แนวทางปฏิบัติที่ดีที่สุดคือการเขียนทริกเกอร์แบบประมวลผลหลายรายการพร้อมกัน ทริกเกอร์แบบประมวลผลหลายรายการพร้อมกันสามารถประมวลผลได้ทั้งข้อมูลรายการเดียวและหลายรายการพร้อมกัน
ไวยากรณ์ของทริกเกอร์ Apex:
trigger TriggerName on ObjectName (trigger_events) {
//Code_block
}
ในที่นี้ TriggerName คือชื่อของทริกเกอร์ ObjectName คือชื่อของวัตถุที่จะเขียนทริกเกอร์ลงไป และ trigger_events คือรายการเหตุการณ์ที่คั่นด้วยเครื่องหมายจุลภาค
ต่อไปนี้คือเหตุการณ์ที่รองรับโดยทริกเกอร์ของ Apex: ก่อนการแทรกข้อมูล, ก่อนการอัปเดตข้อมูล, ก่อนการลบข้อมูล, หลังการแทรกข้อมูล, หลังการอัปเดตข้อมูล, หลังการลบข้อมูล, หลังการกู้คืนข้อมูล
คีย์เวิร์ดแบบ static ไม่สามารถใช้ใน Apex trigger ได้ แต่คีย์เวิร์ดทั้งหมดที่ใช้ได้กับคลาสภายในสามารถใช้ใน Apex trigger ได้
มีตัวแปรโดยปริยายที่กำหนดไว้ในทุกทริกเกอร์ ซึ่งจะส่งคืนบริบทขณะรันไทม์ ตัวแปรเหล่านี้ถูกกำหนดไว้ในคลาส System.Trigger และเรียกว่าตัวแปรบริบท ภาพหน้าจอสองภาพด้านล่างแสดงรายการตัวแปรบริบทที่รองรับโดยทริกเกอร์ของ Apex:
ต่อไปนี้คือข้อควรพิจารณาสำหรับตัวแปรบริบทในทริกเกอร์ของ Apex:
- ห้ามใช้ trigger.new และ trigger.old ในการดำเนินการ DML
- ไม่สามารถลบ Trigger.new ได้
- Trigger.new เป็นแบบอ่านอย่างเดียวใน after triggers
- Trigger.new สามารถใช้เพื่อเปลี่ยนค่าของฟิลด์ในอ็อบเจ็กต์เดียวกันได้เฉพาะก่อนทริกเกอร์เท่านั้น
ภาพหน้าจอสองภาพด้านล่างนี้แสดงข้อควรพิจารณาเกี่ยวกับการดำเนินการเฉพาะในเหตุการณ์ทริกเกอร์ต่างๆ:
ทริกเกอร์จัดการตรรกะแบบเรียลไทม์ แต่บางงานมีขนาดใหญ่เกินกว่าจะจัดการได้ด้วยธุรกรรมเดียว นั่นคือเหตุผลที่ต้องใช้ Apex แบบแบตช์
คลาสแบทช์ในเอเพ็กซ์
คลาสแบบแบตช์ใน Salesforce ใช้สำหรับประมวลผลข้อมูลจำนวนมาก ซึ่งหากประมวลผลตามปกติจะเกินขีดจำกัดของ Apex governor คลาสแบบแบตช์จะเรียกใช้โค้ดแบบอะซิงโครนัส
ต่อไปนี้คือข้อดีของการเรียนแบบกลุ่ม:
- คลาสแบบแบตช์จะประมวลผลข้อมูลเป็นส่วนๆ และหากส่วนใดส่วนหนึ่งประมวลผลไม่สำเร็จ ส่วนที่ประมวลผลสำเร็จแล้วจะไม่ถูกย้อนกลับ
- ข้อมูลแต่ละส่วนในคลาสแบทช์จะถูกประมวลผลด้วยชุดขีดจำกัดของตัวควบคุมใหม่ ซึ่งทำให้มั่นใจได้ว่าโค้ดจะทำงานภายในขีดจำกัดการทำงานของตัวควบคุม
อินเทอร์เฟซ Database.Batchable ต้องถูกใช้งานโดยคลาส Apex เพื่อใช้เป็นคลาสสำหรับการประมวลผลแบบกลุ่ม (batch class) โดยมีเมธอดสามเมธอดที่คลาสสำหรับการประมวลผลแบบกลุ่มนั้นต้องถูกนำไปใช้งาน:
1. เริ่ม()
เมธอดนี้สร้างขอบเขตของเรคอร์ดหรืออ็อบเจ็กต์ที่จะถูกประมวลผลโดยเมธอด execute ของอินเทอร์เฟซ โดยจะถูกเรียกเพียงครั้งเดียวระหว่างการทำงานของแบตช์ เมธอดนี้จะส่งคืนอ็อบเจ็กต์ Database.QueryLocator หรือ Iterable จำนวนเรคอร์ดที่สามารถดึงมาได้โดยการสืบค้น SOQL โดยใช้อ็อบเจ็กต์ Database.QueryLocator คือ 50 ล้านเรคอร์ด แต่หากใช้ Iterable จำนวนเรคอร์ดทั้งหมดที่สามารถดึงมาได้โดยการสืบค้น SOQL จะเหลือเพียง 50,000 เรคอร์ดเท่านั้น Iterable ใช้ในการสร้างขอบเขตที่ซับซ้อนสำหรับคลาสแบตช์
ไวยากรณ์ของเมธอด start:
global (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc) {}
2. execute()
วิธีการนี้ใช้สำหรับประมวลผลข้อมูลแต่ละส่วน โดยจะเรียกใช้เมธอด execute สำหรับแต่ละส่วนของระเบียน ขนาดชุดข้อมูลเริ่มต้นสำหรับการประมวลผลคือ 200 ระเบียน เมธอด execute รับอาร์กิวเมนต์สองตัว:
การอ้างอิงถึงวัตถุ Database.BatchableContext
รายการของ sObject เช่น List หรือรายการของประเภทที่มีพารามิเตอร์ ไวยากรณ์ของเมธอด execute:
global void execute(Database.BatchableContext bc, List<P> records){}
3. finish()
เมธอด `finish` จะถูกเรียกเพียงครั้งเดียวในระหว่างการทำงานของคลาส `batch` สามารถดำเนินการหลังการประมวลผลได้ในเมธอด `finish` เช่น การส่งอีเมลยืนยัน เมธอดนี้จะถูกเรียกเมื่อประมวลผล batch ทั้งหมดเสร็จสิ้นแล้ว ไวยากรณ์ของเมธอด `finish`:
global void finish(Database.BatchableContext bc){}
ฐานข้อมูล.อ็อบเจ็กต์ BatchableContext
แต่ละเมธอดของอินเทอร์เฟซ Database.Batchable จะมีการอ้างอิงถึงอ็อบเจ็กต์ Database.BatchableContext
วัตถุนี้ใช้สำหรับ track คือความคืบหน้าของงานแบบแบตช์
ต่อไปนี้คือเมธอดอินสแตนซ์ที่ BatchableContext จัดเตรียมไว้ให้:
- getChildJobId(): เมธอดนี้จะส่งคืน ID ของงานแบตช์ที่กำลังดำเนินการอยู่
- getJobId(): วิธีการนี้ส่งคืน ID ของงานแบตช์
ด้านล่างนี้คือไวยากรณ์ของคลาสแบตช์:
global class MyBatchClass implements Database.Batchable<sObject> {
global (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc) {
// collect the batches of records or objects to be passed to execute
}
global void execute(Database.BatchableContext bc, List<P> records){
// process each batch of records
}
global void finish(Database.BatchableContext bc){
// execute any post-processing operations
}
}
วิธี Database.executeBatch
เมธอด Database.executeBatch ใช้สำหรับเรียกใช้งานคลาสแบบแบตช์
เมธอดนี้รับพารามิเตอร์สองตัว ได้แก่ อินสแตนซ์ของคลาสแบทช์ที่จะประมวลผล และพารามิเตอร์ขอบเขต (scope) ที่เป็นตัวเลือกเพื่อระบุขนาดแบทช์ หากไม่ได้ระบุไว้ จะใช้ขนาดเริ่มต้นที่ 200
ไวยากรณ์ของ Database.executeBatch:
Database.executeBatch(myBatchObject, scope)
กำลังเรียกใช้คลาสแบตช์ชื่อ MyBatchClass:
MyBatchClass myBatchObject = new MyBatchClass(); Id batchId = Database.executeBatch(myBatchObject, 100);
ฐานข้อมูล.สถานะ
โดยค่าเริ่มต้น คลาส Batch จะไม่มีสถานะ (stateless) ทุกครั้งที่มีการเรียกเมธอด execute ระบบจะได้รับสำเนาใหม่ของอ็อบเจ็กต์ และตัวแปรทั้งหมดของคลาสจะถูกกำหนดค่าเริ่มต้น
Database.Stateful ถูกนำมาใช้เพื่อให้คลาสแบทช์มีสถานะ (stateful)
หากคลาสแบตช์ของคุณใช้งานอินเทอร์เฟซนี้ ฐานข้อมูลอินเทอร์เฟซแบบมีสถานะ (Stateful interface) ตัวแปรอินสแตนซ์ทั้งหมดจะคงค่าเดิมไว้ แต่ตัวแปรสแตติกจะถูกรีเซ็ตระหว่างการทำธุรกรรมแต่ละครั้ง
Apex แบบอะซิงโครนัส นอกเหนือจาก Batch
Batch Apex เป็นเพียงหนึ่งในหลายวิธีในการรันโค้ดแบบอะซิงโครนัส Salesforce มีตัวเลือกอะซิงโครนัสให้เลือกถึงสี่แบบ และการเลือกตัวเลือกที่เหมาะสมนั้นขึ้นอยู่กับปริมาณข้อมูลที่คุณประมวลผล และว่างานเหล่านั้นจำเป็นต้องเชื่อมโยงกันหรือกำหนดเวลาไว้หรือไม่
- วิธีการในอนาคต: เมื่อมีการใส่คำอธิบายประกอบ @future ไว้ โค้ดเหล่านี้เหมาะที่สุดสำหรับการดำเนินการแบบง่ายๆ ที่ต้องการเรียกใช้แล้วจบ เช่น การเรียกใช้เว็บเซอร์วิสภายนอก
- Apex ที่สามารถเข้าคิวได้: ใช้งานอินเทอร์เฟซ Queueable รองรับประเภทอ็อบเจ็กต์ที่ซับซ้อน ส่งคืนรหัสงาน และรองรับการเชื่อมโยงงานหนึ่งไปยังอีกงานหนึ่ง
- แบตช์ เอเพ็กซ์: ประมวลผลข้อมูลปริมาณมหาศาลเป็นส่วนๆ ตามที่อธิบายไว้ข้างต้น
- กำหนดการ Apex: ใช้งานอินเทอร์เฟซ Schedulable เพื่อให้คลาสทำงานในเวลาที่กำหนด เช่น งานล้างข้อมูลตอนกลางคืน
| ประเภท | ที่ดีที่สุดสำหรับ | ความสามารถหลัก |
|---|---|---|
| วิธีการในอนาคต | คำอธิบายง่ายๆ | ติดตั้งแล้วก็ไม่ต้องดูแลอีกต่อไป |
| Apex ที่สามารถเข้าคิวได้ | การประมวลผลตามลำดับ | การเชื่อมโยงและติดตามงาน |
| แบตช์เอเพ็กซ์ | บันทึกนับล้านรายการ | การประมวลผลแบบแบ่งเป็นชิ้น |
| กำหนด Apex | งานที่ทำซ้ำ | การกำหนดเวลาตาม Cron |
ไม่ว่าคุณจะเลือกรูปแบบการดำเนินการแบบใด ทุกธุรกรรมจะยังคงถูกวัดเทียบกับขีดจำกัดการควบคุมทั่วทั้งแพลตฟอร์มที่ระบุไว้ด้านล่าง
ขีดจำกัดผู้ว่าการเอเพ็กซ์
ข้อจำกัดของ Apex Governor Limits คือข้อจำกัดที่บังคับใช้โดย Apex Runtime Engine เพื่อให้แน่ใจว่าโค้ดและกระบวนการ Apex ที่ทำงานผิดปกติจะไม่ผูกขาดทรัพยากรที่ใช้ร่วมกัน และจะไม่รบกวนการประมวลผลของผู้ใช้รายอื่นในสภาพแวดล้อมแบบ Multi-tenant ข้อจำกัดเหล่านี้จะได้รับการตรวจสอบกับแต่ละธุรกรรม Apex ต่อไปนี้คือข้อจำกัดของ Governor Limits ที่ Salesforce กำหนดไว้สำหรับแต่ละธุรกรรม Apex:
| Descriptไอออน | ลิมิตสวิตช์ |
|---|---|
| แบบสอบถาม SOQL ที่สามารถทำได้ในธุรกรรมแบบซิงโครนัส | 100 |
| คำสั่ง SOQL ที่สามารถดำเนินการได้ในธุรกรรมแบบอะซิงโครนัส | 200 |
| บันทึกที่สามารถดึงข้อมูลได้โดยการสืบค้น SOQL | 50,000 |
| บันทึกที่สามารถดึงข้อมูลได้โดย Database.getQueryLocator | 10,000 |
| คำสั่ง SOSL ที่สามารถดำเนินการได้ในธุรกรรม Apex | 20 |
| บันทึกที่สามารถดึงข้อมูลได้โดยแบบสอบถาม SOSL | 2,000 |
| คำสั่ง DML ที่สามารถดำเนินการได้ในธุรกรรม Apex | 150 |
| เรกคอร์ดที่สามารถประมวลผลเป็นผลจากคำสั่ง DML, Approval.process หรือ Database.emptyRecycleBin | 10,000 |
| การเรียกใช้ฟังก์ชันต่างๆ ที่สามารถทำได้ในธุรกรรม Apex | 100 |
| ขีดจำกัดเวลาหมดอายุสะสมสำหรับการเรียกใช้ทั้งหมดที่ดำเนินการในธุรกรรม Apex | วินาที 120 |
| จำกัดจำนวนงาน Apex ที่สามารถเพิ่มลงในคิวด้วย System.enqueueJob | 50 |
| กำหนดเวลาดำเนินการสำหรับธุรกรรม Apex แต่ละรายการ | 10 นาที |
| มีข้อจำกัดเกี่ยวกับจำนวนตัวอักษรที่สามารถใช้ในคลาสและทริกเกอร์ของ Apex ได้ | 1 ล้าน |
| ขีดจำกัดเวลา CPU สำหรับธุรกรรมแบบซิงโครนัส | 10,000 มิลลิวินาที |
| ขีดจำกัดเวลา CPU สำหรับธุรกรรมแบบอะซิงโครนัส | 60,000 มิลลิวินาที |
| ขนาดฮีปทั้งหมด | 6 MB (แบบซิงโครนัส) / 12 MB (แบบอะซิงโครนัส) |
วิธีการเขียนคลาสทดสอบใน Apex
Salesforce กำหนดให้โค้ด Apex ของคุณอย่างน้อย 75 เปอร์เซ็นต์ต้องได้รับการทดสอบด้วย Unit Test ก่อนที่จะนำไปใช้งานจริง และทุก Trigger ต้องมีการทดสอบในระดับหนึ่ง การเขียน Test Class จึงเป็นทักษะหลักของ Apex ไม่ใช่สิ่งที่ไม่จำเป็นเพิ่มเติม
คลาสทดสอบจะถูกระบุด้วยคำอธิบายประกอบ @isTest และแต่ละเมธอดทดสอบก็ถูกทำเครื่องหมายด้วย @isTest เช่นกัน เมธอดทดสอบจะไม่บันทึกข้อมูลลงในฐานข้อมูลและจะไม่เห็นข้อมูลส่วนใหญ่ที่มีอยู่ขององค์กร ดังนั้นแต่ละการทดสอบจึงสร้างเรคอร์ดของตัวเอง เมธอด Test.startTest() และ Test.stopTest() จะกำหนดขีดจำกัดของ Governor Limit ชุดใหม่ให้กับโค้ดที่กำลังทดสอบ และการตรวจสอบจะยืนยันว่าตรรกะทำงานได้ตามที่คาดไว้
นี่คือคลาสทดสอบอย่างง่ายสำหรับตรรกะการสร้างบัญชี:
@isTest
private class AccountHandlerTest {
@isTest
static void testCreateAccount() {
Account acc = new Account(Name = 'Test Account');
Test.startTest();
insert acc;
Test.stopTest();
Account result = [SELECT Id, Name FROM Account WHERE Id = :acc.Id];
System.assertEquals('Test Account', result.Name);
}
}
โปรดปฏิบัติตามแนวทางเหล่านี้เมื่อเขียนข้อสอบ:
- ใช้เมธอด @testSetup เพื่อสร้างข้อมูลทดสอบที่ใช้ร่วมกันเพียงครั้งเดียวสำหรับเมธอดทดสอบทั้งหมดในคลาส
- ทดสอบการทำงานแบบกลุ่มโดยการแทรกข้อมูล 200 รายการ ไม่ใช่แค่รายการเดียว
- ครอบคลุมสถานการณ์การใช้งานทั้งในเชิงบวก เชิงลบ และแบบจำกัดสิทธิ์ผู้ใช้
- ควรใส่คำสั่ง System.assert ที่มีความหมายเสมอ การตรวจสอบความครอบคลุมโดยไม่มีคำสั่ง assertion นั้นพิสูจน์อะไรไม่ได้เลย
แนวปฏิบัติที่ดีที่สุดของ Apex
ผู้เริ่มต้นมักเขียนโค้ด Apex ที่ใช้ได้กับข้อมูลเพียงรายการเดียว แต่ใช้งานไม่ได้กับข้อมูลจำนวนมากในโลกแห่งความเป็นจริง แนวทางปฏิบัติด้านล่างนี้จะช่วยให้โค้ดของคุณอยู่ในขอบเขตที่กำหนดและดูแลรักษาง่ายขึ้น:
- รวมทุกอย่างไว้ในปริมาณมาก: เขียนโค้ดที่สามารถจัดการกับชุดข้อมูลจำนวนมากได้ เนื่องจากทริกเกอร์สามารถรับข้อมูลได้มากถึง 200 รายการในคราวเดียว
- อย่าใช้ SOQL และ DML ในลูป: สอบถามข้อมูลก่อนเริ่มลูป รวบรวมการเปลี่ยนแปลงไว้ในรายการ และดำเนินการคำสั่ง DML หนึ่งคำสั่งหลังจากลูปเสร็จสิ้น
- หนึ่งทริกเกอร์ต่อหนึ่งวัตถุ: ควรทำให้ทริกเกอร์ไม่มีตรรกะการทำงานที่ซับซ้อน และมอบหมายงานให้คลาสตัวจัดการ ซึ่งจะทำให้ลำดับการทำงานสามารถคาดเดาได้
- ใช้ร่วมกันได้: บังคับใช้การรักษาความปลอดภัยระดับระเบียน เว้นแต่จะมีเหตุผลที่ระบุไว้เป็นลายลักษณ์อักษรให้ดำเนินการในบริบทของระบบ
- หลีกเลี่ยงการกำหนดรหัส ID แบบตายตัว: รหัสบันทึก (Record ID) จะแตกต่างกันระหว่างสภาพแวดล้อมทดสอบ (sandbox) และสภาพแวดล้อมการใช้งานจริง (production) ดังนั้นจึงต้องค้นหารหัสบันทึกเหล่านั้น หรือใช้เมตาเดตาแบบกำหนดเอง (Custom Metadata) แทน
- ตรวจสอบข้อจำกัดในการเขียนโค้ด: เมธอดของคลาส Limits เช่น Limits.getQueries() ช่วยให้คุณตรวจสอบการใช้ทรัพยากรขณะรันไทม์ได้
💡 เคล็ดลับ: ทดสอบโค้ดของคุณกับข้อมูล 200 ชุดในสภาพแวดล้อมทดสอบก่อนที่จะนำไปใช้งานจริง ความล้มเหลวของข้อจำกัดของ Governor Limit ส่วนใหญ่มักเกิดขึ้นเมื่อใช้งานกับข้อมูลจำนวนมาก และการตรวจพบปัญหาตั้งแต่เนิ่นๆ นั้นประหยัดกว่าการแก้ไขข้อผิดพลาดในสภาพแวดล้อมการใช้งานจริงมาก






