دليل تعليمي لـ Salesforce Apex للمبتدئين
⚡ ملخص ذكي
توفر لغة برمجة Apex لمطوري Salesforce لغةً كائنية التوجه ذات كتابة قوية لإضافة منطق أعمال مخصص إلى نظام إدارة علاقات العملاء (CRM). وهي تدعم الفئات والمشغلات ووظائف الدفعات، بينما تحافظ حدود الحوكمة على استقرار المنصة المشتركة متعددة المستأجرين.

ما هو أبيكس في 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) و SOSL (لغة بحث كائنات Salesforce) في Apex.
- يسمح لك بإنشاء ملف اختبار الوحدة وتنفيذه للتحقق من مدونة التغطية وكفاءة الكود في لغة Apex.
- يتم تنفيذ Apex في بيئة متعددة المستأجرين، و ساليسفورسي تم تحديد حدود إدارية تمنع المستخدم من احتكار الموارد المشتركة. أي كود يتجاوز هذه الحدود يفشل، ويظهر خطأ.
- يمكن استخدام كائن Salesforce كنوع بيانات في لغة Apex. على سبيل المثال:
Account acc = new Account();
هنا، الحساب هو كائن قياسي في Salesforce.
- يتم ترقية Apex تلقائيًا مع كل إصدار من Salesforce.
متى ينبغي على المطور اختيار لغة Apex؟
لا ينبغي كتابة كود Apex إلا إذا كان سيناريو العمل معقدًا للغاية بحيث لا يمكن تنفيذه باستخدام الوظائف الجاهزة التي توفرها Salesforce والتي تعتمد على النقر والتحديد.
فيما يلي بعض السيناريوهات التي تتطلب كتابة كود Apex:
- لإنشاء خدمات ويب تدمج Salesforce مع التطبيقات الأخرى.
- لتطبيق التحقق المخصص على كائنات sObjects.
- لتنفيذ منطق Apex مخصص عند إجراء عملية DML.
- لتنفيذ وظائف لا يمكن بناؤها باستخدام أدوات الأتمتة التصريحية الحالية مثل Flow.
- للإعداد خدمات البريد الإلكتروني التي تعالج محتويات البريد الإلكتروني الوارد وعناوينه ومرفقاته.
بمجرد أن تعرف متى يكون Apex هو الخيار الصحيح، فإن الخطوة التالية هي فهم ما يحدث لرمزك بعد حفظه.
الهيكل التنظيمي لشركة Apex
فيما يلي تسلسل الإجراءات الخاصة بكود Apex:
- إجراء المطور: عندما يقوم المطور بحفظ التعليمات البرمجية على النظام الأساسي، يتم تجميع جميع تعليمات Apex البرمجية في مجموعة من التعليمات التي يمكن لمفسر وقت تشغيل Apex فهمها، ثم يتم حفظ هذه التعليمات كبيانات وصفية على النظام الأساسي.
- إجراء المستخدم النهائي: عندما يقوم حدث المستخدم بتنفيذ كود Apex، يقوم خادم النظام الأساسي باسترداد التعليمات المجمعة من البيانات الوصفية وتشغيلها من خلال مترجم Apex قبل إرجاع النتيجة.
يوضح الرسم البياني أدناه كيفية تفاعل إجراءات المطور والمستخدم النهائي مع خادم تطبيقات منصة Lightning:
بيئة تطوير أبيكس
يمكن تطوير كود Apex إما في بيئة تجريبية أو في مؤسسة إصدار المطورين من Salesforce.
من أفضل الممارسات تطوير الكود في بيئة تجريبية (sandbox) ثم نشره في بيئة الإنتاج، كما هو موضح أدناه:
أدوات تطوير كود Apex: فيما يلي الأدوات الثلاث المتاحة لتطوير كود Apex في جميع إصدارات Salesforce:
- وحدة تحكم المطور
- Visual Studio Code مع حزمة ملحقات Salesforce (هذا يحل محل بيئة التطوير المتكاملة Force.com المتقاعدة)
- Code محرر في واجهة مستخدم إعداد Salesforce
بعد تجهيز بيئتك، دعنا نلقي نظرة على اللبنات الأساسية للغة نفسها، بدءًا من أنواع البيانات.
أنواع البيانات في لغة Apex
فيما يلي أنواع البيانات التي يدعمها Apex:
بدائي
عدد صحيح، Doubleتُعتبر الأنواع Long وDate وDatetime وDecimal وTime وBlob وString وID وBoolean أنواع بيانات أساسية. تُمرر جميع أنواع البيانات الأساسية بالقيمة، وليس بالمرجع.
المجموعات
تتوفر ثلاثة أنواع من المجموعات في Apex:
- قائمة: إنها مجموعة مرتبة من العناصر الأولية، أو كائنات sObjects، أو المجموعات، أو كائنات Apex بناءً على الفهارس.
- تعيين: مجموعة غير مرتبة من العناصر الفريدة التي لا تحتوي على عناصر مكررة.
- الخريطة: إنها مجموعة من المفاتيح الفريدة التي ترتبط بقيم مفردة، والتي يمكن أن تكون بدائية أو كائنات sObjects أو مجموعات أو كائنات Apex.
كائن
هذا نوع بيانات خاص في Salesforce. إنه مشابه لجدول في SQL ويحتوي على حقول مشابهة للأعمدة في لغة SQL.
تتضمن التعدادات
التعداد هو مطلقtracنوع بيانات t يخزن قيمة واحدة من مجموعة محدودة من المعرفات المحددة.
الفئات والكائنات والواجهات
يمكن أيضًا استخدام فئات وواجهات Apex المُعرَّفة من قِبل المستخدم كأنواع بيانات. يشير الكائن إلى نسخة من أي نوع بيانات مدعوم في Apex.
بناء جملة أبيكس
إعلان متغير
بما أن Apex لغة ذات كتابة قوية، فمن الضروري تعريف متغير بنوع بيانات في Apex.
فمثلا:
Contact con = new Contact();
هنا تم تعريف المتغير con بنوع بيانات Contact.
استعلام SOQL
لغة SOQL هي اختصار لـ Salesforce Object Query Language (لغة استعلام كائنات Salesforce). تُستخدم هذه اللغة لجلب سجلات 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 داخل مساحة اسم.
خاص
يُتيح مُحدِّد الوصول هذا إمكانية الوصول إلى فئة أو دالة أو متغير لاستخدامه محليًا، أو ضمن قسم الكود الذي تم تعريفه فيه. جميع الدوال والمتغيرات التي لم يتم تعريف مُحدِّد وصول لها تأخذ مُحدِّد الوصول الافتراضي وهو "خاص".
محمي
يُتيح مُحدد الوصول هذا الوصول إلى طريقة أو متغير ليتم استخدامه بواسطة أي فئات داخلية ضمن فئة Apex المُحددة.
تجوال حول العالم
يُتيح مُحدِّد الوصول هذا إمكانية الوصول إلى فئة أو دالة أو متغير لاستخدامها بواسطة Apex داخل نطاق اسمي وخارجه. ومن أفضل الممارسات عدم استخدام الكلمة المفتاحية global إلا عند الضرورة.
الكلمات الرئيسية في أبيكس
مع المشاركة
إذا تم تعريف فئة باستخدام هذه الكلمة المفتاحية، فسيتم تطبيق جميع قواعد المشاركة المطبقة على المستخدم الحالي. أما إذا لم يتم استخدام هذه الكلمة المفتاحية، فسيتم تنفيذ الكود ضمن سياق النظام.
فمثلا:
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 مرة واحدة فقط، ثم تُربط بالفئة. ويمكن استدعاء المتغيرات والدوال الثابتة مباشرةً باسم الفئة دون الحاجة إلى إنشاء نسخة منها.
نهائي
لا يمكن تجاوز ثابت أو دالة مُعرَّفة باستخدام الكلمة المفتاحية final. على سبيل المثال:
public class myCls {
static final Integer INT_CONST = 10;
}
إذا حاولت تجاوز قيمة متغير INT_CONST هذا، فستحصل على الاستثناء – System.FinalException: تم تهيئة المتغير النهائي بالفعل.
الإرجاع
ترجع هذه الكلمة الأساسية قيمة من إحدى الطرق. على سبيل المثال:
public String getName() {
return 'Test';
}
فارغة
يُعرّف هذا الثابت قيمة فارغة ويمكن إسناده إلى متغير. على سبيل المثال:
Boolean b = null;
افتراضي
إذا تم تعريف فئة باستخدام الكلمة المفتاحية virtual، فيمكن توسيعها وتجاوزها.
الملخص
إذا تم تعريف فئة باستخدام القيمة المطلقةtracيجب أن تحتوي الكلمة المفتاحية t على طريقة واحدة على الأقل باستخدام الكلمة المفتاحية abstract، ويجب أن تحتوي هذه الطريقة على توقيع فقط.
فمثلا:
public abstract class MyAbstractClass {
abstract Integer myAbstractMethod1();
}
سلسلة أبيكس
السلسلة النصية هي مجموعة من الأحرف بدون حد أقصى لعدد الأحرف. على سبيل المثال:
String name = 'Test';
تتضمن فئة String في Salesforce عدة طرق مدمجة. فيما يلي بعض الطرق الأكثر استخدامًا:
اختصار (العرض الأقصى)
تقوم هذه الطريقة باقتطاع سلسلة نصية إلى الطول المحدد، وتعيدها إذا كان طول السلسلة المُعطاة أطول من الطول المحدد؛ وإلا، فإنها تُعيد السلسلة الأصلية. إذا كانت قيمة المتغير 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);
يحتوي على (سلسلة فرعية)
تُرجع هذه الطريقة القيمة "صحيح" إذا كانت السلسلة التي تستدعي الطريقة تحتوي على السلسلة الفرعية المحددة.
String name1 = 'test1';
String name2 = 'test';
Boolean flag = name1.contains(name2);
System.debug('flag:: ' + flag); //true
يساوي (stringOrId)
تُرجع هذه الطريقة القيمة "صحيح" إذا لم يكن المعامل المُمرر فارغًا ويمثل نفس التسلسل الثنائي للأحرف مثل السلسلة التي تستدعي الطريقة.
عند مقارنة قيم المعرّفات، قد لا تتساوى أطوالها. على سبيل المثال، إذا قورنت سلسلة نصية تمثل معرّفًا مكونًا من 15 حرفًا مع كائن يمثل معرّفًا مكونًا من 18 حرفًا، فإن هذه الطريقة تُرجع القيمة "صحيح". على سبيل المثال:
String stringValue15 = '001D000000Ju1zH';
Id idValue18 = '001D000000Ju1zHIAR';
Boolean result = stringValue15.equals(idValue18);
System.debug('result: ' + result); //true
في المثال أعلاه، تقارن طريقة equals معرف كائن مكون من 15 حرفًا بمعرف كائن مكون من 18 حرفًا، وإذا كان كلا المعرفين يمثلان نفس التسلسل الثنائي، فإنها تُرجع القيمة true.
استخدم هذا الأسلوب لإجراء مقارنات حساسة لحالة الأحرف.
escapeSingleQuotes(stringToEscape)
تُضيف هذه الطريقة حرف الهروب (\) قبل أي علامة اقتباس مفردة في سلسلة نصية، ثم تُعيد النتيجة. تمنع هذه الطريقة هجمات حقن SOQL أثناء إنشاء استعلام 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
- صفحة تفاصيل فئة 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). تُستخدم هاتان الدالتان لتنفيذ التعليمات البرمجية قبل الوصول إلى قيمة الخاصية أو تغييرها. تُنفذ التعليمات البرمجية في دالة الجلب عند قراءة قيمة الخاصية، بينما تُنفذ التعليمات البرمجية في دالة التعيين عند تغييرها. تُعتبر أي خاصية تحتوي على دالة جلب فقط للقراءة فقط، وأي خاصية تحتوي على دالة تعيين فقط للكتابة فقط، وأي خاصية تحتوي على دالتي جلب وتعيين تُعتبر للقراءة والكتابة. صيغة تعريف خاصية 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 النوعين التاليين من المحفزات:
قبل حدوث المحفزات: تُستخدم هذه المحفزات للتحقق من صحة قيمة الحقل وتحديثها قبل حفظ السجل في قاعدة البيانات.
بعد حدوث المحفزات: تُستخدم هذه المُشغّلات للوصول إلى قيم الحقول (مثل مُعرّف السجل وحقل تاريخ آخر تعديل) التي يُعيّنها النظام بعد إضافة السجل إلى قاعدة البيانات. يُمكن استخدام قيم هذه الحقول لتعديل سجلات أخرى. السجلات التي يتم تشغيلها بعد المُشغّلات تكون للقراءة فقط.
من أفضل الممارسات كتابة مشغلات معالجة البيانات المجمعة. يمكن لمشغل معالجة البيانات المجمعة معالجة سجل واحد أو عدة سجلات في وقت واحد.
صيغة مُشغّل Apex:
trigger TriggerName on ObjectName (trigger_events) {
//Code_block
}
هنا، TriggerName هو اسم المشغل، وObjectName هو اسم الكائن الذي تمت كتابة المشغل عليه، وtrigger_events هي قائمة أحداث مفصولة بفواصل.
فيما يلي الأحداث التي تدعمها مشغلات Apex: قبل الإدراج، قبل التحديث، قبل الحذف، بعد الإدراج، بعد التحديث، بعد الحذف، بعد استعادة الحذف.
لا يمكن استخدام الكلمات المفتاحية الثابتة في مُشغّل Apex. يمكن استخدام جميع الكلمات المفتاحية التي تنطبق على الفئات الداخلية في مُشغّل Apex.
تُعرّف كل مُشغّل متغيرات ضمنية تُعيد سياق وقت التشغيل. تُعرّف هذه المتغيرات في فئة System.Trigger وتُسمى متغيرات السياق. تُظهر لقطتا الشاشة أدناه متغيرات السياق التي تدعمها مُشغّلات Apex:
فيما يلي الاعتبارات المتعلقة بمتغيرات السياق في مشغلات Apex:
- لا تستخدم trigger.new و trigger.old في عمليات DML.
- لا يمكن حذف ملف Trigger.new.
- يكون Trigger.new للقراءة فقط في عمليات التشغيل اللاحقة.
- يمكن استخدام Trigger.new لتغيير قيم الحقول في نفس الكائن في المشغلات السابقة فقط.
توضح لقطتا الشاشة أدناه الاعتبارات المتعلقة بإجراءات محددة في أحداث التشغيل المختلفة:
تتولى المشغلات معالجة المنطق في الوقت الفعلي، لكن بعض المهام تكون ببساطة أكبر من أن تُنفذ في معاملة واحدة. وهنا يأتي دور لغة Apex المجمعة.
فئة دفعة في أبيكس
تُستخدم فئة المعالجة الدفعية في Salesforce لمعالجة عدد كبير من السجلات التي قد تتجاوز حدود Apex Governor إذا تمت معالجتها بالطريقة العادية. وتقوم فئة المعالجة الدفعية بتنفيذ التعليمات البرمجية بشكل غير متزامن.
فيما يلي مزايا فئة الدفعات:
- تقوم فئة المعالجة الدفعية بمعالجة البيانات على شكل أجزاء، وإذا فشلت معالجة جزء واحد بنجاح، فلن يتم التراجع عن الأجزاء التي تمت معالجتها بنجاح.
- تتم معالجة كل جزء من البيانات في فئة الدفعة بمجموعة جديدة من حدود الحوكمة، مما يضمن تنفيذ التعليمات البرمجية ضمن حدود تنفيذ الحوكمة.
يجب على فئة Apex تطبيق واجهة Database.Batchable لاستخدامها كفئة معالجة دفعية. توفر هذه الواجهة ثلاث طرق يجب على فئة المعالجة الدفعية تطبيقها:
1. start()
تُنشئ هذه الطريقة نطاق السجلات أو الكائنات التي ستُعالج بواسطة طريقة التنفيذ في الواجهة. ويتم استدعاؤها مرة واحدة فقط أثناء تنفيذ الدفعة. تُعيد هذه الطريقة إما كائن Database.QueryLocator أو كائن Iterable. يبلغ عدد السجلات التي يمكن استرجاعها بواسطة استعلام SOQL باستخدام كائن Database.QueryLocator خمسين مليون سجل، بينما يبلغ هذا العدد خمسين ألف سجل فقط عند استخدام كائن Iterable. يُستخدم كائن Iterable لإنشاء نطاق مُعقد لفئة الدفعة.
صيغة طريقة البدء:
global (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc) {}
2. execute()
تُستخدم هذه الطريقة لمعالجة كل جزء من البيانات. يتم استدعاء دالة التنفيذ لكل جزء من السجلات. حجم الدفعة الافتراضي للتنفيذ هو 200 سجل. تأخذ دالة التنفيذ وسيطين:
إشارة إلى كائن Database.BatchableContext،
قائمة من الكائنات، مثل List أو قائمة بأنواع مُعاملة. صيغة دالة التنفيذ:
global void execute(Database.BatchableContext bc, List<P> records){}
3. إنهاء()
يتم استدعاء دالة الإنهاء مرة واحدة أثناء تنفيذ فئة الدُفعة. ويمكن إجراء عمليات ما بعد المعالجة في دالة الإنهاء، مثل إرسال بريد إلكتروني للتأكيد. تُستدعى هذه الدالة عند معالجة جميع الدُفعات. صيغة دالة الإنهاء:
global void finish(Database.BatchableContext bc){}
كائن Database.BatchableContext
تحتوي كل طريقة من طرق واجهة Database.Batchable على مرجع إلى كائن Database.BatchableContext.
يُستخدم هذا العنصر لـ track تقدم عملية المعالجة الدفعية.
فيما يلي طرق النسخ التي يوفرها BatchableContext:
- getChildJobId(): تُرجع هذه الطريقة معرف مهمة الدفعة التي تتم معالجتها حاليًا.
- getJobId(): تقوم هذه الطريقة بإرجاع معرف المهمة المجمعة.
فيما يلي صيغة فئة الدفعات:
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 لتنفيذ فئة دفعية.
تأخذ هذه الطريقة مُعاملين: نسخة من فئة الدفعة المراد معالجتها، ومُعامل نطاق اختياري لتحديد حجم الدفعة. إذا لم يتم تحديده، فسيتم استخدام الحجم الافتراضي 200.
صيغة الأمر Database.executeBatch:
Database.executeBatch(myBatchObject, scope)
تنفيذ فئة دفعية باسم MyBatchClass:
MyBatchClass myBatchObject = new MyBatchClass(); Id batchId = Database.executeBatch(myBatchObject, 100);
قاعدة البيانات. ذات الحالة
تكون فئة الدفعات عديمة الحالة افتراضياً. في كل مرة يتم فيها استدعاء طريقة التنفيذ، يتم استلام نسخة جديدة من الكائن، ويتم تهيئة جميع متغيرات الفئة.
تم تطبيق Database.Stateful لجعل فئة الدفعات ذات حالة.
إذا كانت فئة الدفعة الخاصة بك تُنفذ قاعدة البياناتواجهة ذات حالة، تحتفظ جميع متغيرات المثيل بقيمها، ولكن يتم إعادة تعيين المتغيرات الثابتة بين المعاملات.
Apex غير المتزامن يتجاوز المعالجة الدفعية
يُعدّ Batch Apex أحد الطرق العديدة لتشغيل التعليمات البرمجية بشكل غير متزامن. توفر Salesforce أربعة خيارات غير متزامنة، ويعتمد اختيار الخيار المناسب على حجم البيانات التي تعالجها وما إذا كانت هناك حاجة إلى ربط المهام أو جدولتها.
- الأساليب المستقبلية: تُعد هذه العمليات، التي يتم شرحها باستخدام @future، الأفضل للعمليات البسيطة التي تُنفذ دون الحاجة إلى إعادة تشغيل، مثل استدعاء خدمات الويب الخارجية.
- قمة قابلة للإضافة إلى قائمة الانتظار: ينفذ واجهة Queueable، ويقبل أنواع الكائنات المعقدة، ويعيد معرف المهمة، ويدعم ربط مهمة بأخرى.
- Batch Apex: يقوم بمعالجة كميات كبيرة جدًا من البيانات على شكل أجزاء، كما هو موضح أعلاه.
- القمة المجدولة: ينفذ واجهة Schedulable بحيث يتم تشغيل فئة في وقت محدد، مثل مهمة التنظيف الليلية.
| النوع | أفضل من أجل | القدرة الرئيسية |
|---|---|---|
| أسلوب المستقبل | إشارات بسيطة | أطلق النار وانساها |
| قمة قابلة للانتظار | المعالجة المتسلسلة | ربط المهام ومراقبتها |
| دفعة أبيكس | ملايين السجلات | معالجة الأجزاء |
| قمة مجدولة | الوظائف المتكررة | التوقيت القائم على Cron |
أياً كان نموذج التنفيذ الذي تختاره، فإن كل معاملة لا تزال تُقاس وفقاً لحدود الحوكمة على مستوى المنصة المدرجة أدناه.
حدود حاكم أبيكس
حدود إدارة Apex هي القيود التي يفرضها محرك تشغيل Apex لضمان عدم استئثار أي كود أو عملية Apex غير منضبطة بالموارد المشتركة، وعدم تعطيل معالجة المستخدمين الآخرين في بيئة متعددة المستأجرين. يتم التحقق من هذه الحدود لكل معاملة Apex. فيما يلي حدود الإدارة التي تحددها Salesforce لكل معاملة Apex:
| الوصف | قصر |
|---|---|
| استعلامات SOQL التي يمكن إجراؤها في معاملة متزامنة | 100 |
| استعلامات SOQL التي يمكن تنفيذها في معاملة غير متزامنة | 200 |
| السجلات التي يمكن استرجاعها بواسطة استعلام SOQL | 50,000 |
| السجلات التي يمكن استردادها بواسطة Database.getQueryLocator | 10,000 |
| استعلامات SOSL التي يمكن إجراؤها في معاملة Apex | 20 |
| السجلات التي يمكن استرجاعها عن طريق استعلام SOSL | 2,000 |
| عبارات DML التي يمكن تنفيذها في معاملة Apex | 150 |
| السجلات التي يمكن معالجتها كنتيجة لبيان DML، أو Approval.process، أو data.emptyRecycleBin | 10,000 |
| الاستدعاءات التي يمكن إجراؤها في معاملة Apex | 100 |
| الحد الأقصى للمهلة الزمنية التراكمية لجميع عمليات الاستدعاء التي يتم تنفيذها في معاملة Apex | 120 ثانية |
| تحديد عدد مهام Apex التي يمكن إضافتها إلى قائمة الانتظار باستخدام System.enqueueJob | 50 |
| الحد الزمني للتنفيذ لكل معاملة Apex | 10 دقائق |
| الحد الأقصى لعدد الأحرف التي يمكن استخدامها في فئة Apex والمشغل | 1 مليون |
| الحد الزمني لوحدة المعالجة المركزية للمعاملة المتزامنة | 10,000 ميلي ثانية |
| الحد الزمني لوحدة المعالجة المركزية للمعاملات غير المتزامنة | 60,000 ميلي ثانية |
| إجمالي حجم الكومة | 6 ميجابايت (متزامن) / 12 ميجابايت (غير متزامن) |
كيفية كتابة فئة اختبار في لغة Apex
تشترط Salesforce أن يكون 75% على الأقل من كود Apex الخاص بك مغطى باختبارات الوحدة قبل نشره في بيئة الإنتاج، ويجب أن يشمل كل مُشغّل بعض الاختبارات. لذا، تُعد كتابة فئات الاختبار مهارة أساسية في Apex، وليست إضافة اختيارية.
تُعلَّم فئة الاختبار بالتعليق التوضيحي @isTest، كما تُعلَّم كل طريقة اختبار بالتعليق التوضيحي @isTest أيضًا. لا تُضيف طرق الاختبار بيانات إلى قاعدة البيانات، ولا ترى معظم بيانات المؤسسة الموجودة، لذا يُنشئ كل اختبار سجلاته الخاصة. تُحدِّد الطريقتان Test.startTest() و Test.stopTest() مجموعة جديدة من حدود الحوكمة للكود قيد الاختبار، وتتحقق التأكيدات من أن المنطق قد عمل كما هو متوقع.
إليك فئة اختبار بسيطة لمنطق إنشاء الحساب:
@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 ذات معنى؛ فالتغطية بدون تأكيدات لا تثبت شيئًا.
أبيكس الممارسات
كثيرًا ما يكتب المبتدئون أكواد Apex تعمل مع سجل واحد فقط، لكنها تفشل في عمليات المعالجة الجماعية في الواقع العملي. تساعد الممارسات التالية في الحفاظ على الكود ضمن حدود الضوابط، وتجعله أسهل في الصيانة:
- قم بتجميع كل شيء: اكتب منطقًا يتعامل مع مجموعات السجلات، لأن المشغلات يمكن أن تتلقى ما يصل إلى 200 سجل في دفعة واحدة.
- تجنب استخدام SOQL وDML في الحلقات: استعلم قبل الحلقة، واجمع التغييرات في قائمة، ونفذ عبارة DML واحدة بعد الحلقة.
- مُشغّل واحد لكل كائن: حافظ على منطق المشغلات خالياً من التعقيدات وقم بتفويض العمل إلى فئات المعالجة، مما يجعل ترتيب التنفيذ قابلاً للتنبؤ.
- استخدمه مع المشاركة: فرض أمان على مستوى السجلات ما لم يكن هناك سبب موثق للتشغيل في سياق النظام.
- تجنب تضمين المعرفات بشكل ثابت في الكود: تختلف معرفات السجلات بين بيئات الاختبار والإنتاج، لذا استعلم عنها أو استخدم بيانات مخصصة بدلاً من ذلك.
- مراقبة الحدود في الكود: تتيح لك طرق فئة Limits، مثل Limits.getQueries()، التحقق من استهلاك الموارد في وقت التشغيل.
؟؟؟؟ تلميح: قم بتشغيل الكود الخاص بك على 200 سجل في بيئة تجريبية قبل النشر. تظهر معظم حالات فشل حدود الحوكمة فقط عند التعامل مع كميات كبيرة من البيانات، واكتشافها مبكراً أرخص بكثير من تصحيحها في بيئة الإنتاج.






