Apex - Краткое руководство

Что такое Апекс?

Apex - это проприетарный язык, разработанный Salesforce.com. Согласно официальному определению, Apex - это строго типизированный объектно-ориентированный язык программирования, который позволяет разработчикам выполнять операторы управления потоком и транзакциями на сервере платформы Force.com в сочетании с вызовами Force.com API.

Он имеет синтаксис, подобный Java, и действует как хранимые процедуры базы данных. Он позволяет разработчикам добавлять бизнес-логику к большинству системных событий, включая нажатия кнопок, обновления связанных записей и Visualforce.pages.Apexкод может быть инициирован запросами веб-службы и триггерами объектов. 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 следует использовать, когда мы не можем реализовать сложные бизнес-функции, используя готовые и существующие готовые функции. Ниже приведены случаи, когда нам нужно использовать конфигурацию apex вместо Salesforce.

Приложения Apex

Мы можем использовать Apex, когда захотим -

  • Создавайте веб-сервисы с интеграцией других систем.

  • Создавайте почтовые службы для рассылки электронной почты или настройки электронной почты.

  • Выполняйте комплексную проверку нескольких объектов одновременно, а также настраиваемую реализацию проверки.

  • Создавайте сложные бизнес-процессы, которые не поддерживаются существующими функциями или потоками рабочих процессов.

  • Создавайте настраиваемую транзакционную логику (логику, которая происходит во всей транзакции, а не только с одной записью или объектом), например, используя методы базы данных для обновления записей.

  • Выполните некоторую логику при изменении записи или измените запись связанного объекта, когда есть какое-то событие, которое вызвало срабатывание триггера.

Рабочая структура Apex

Как показано на диаграмме ниже (Ссылка: документация для разработчиков Salesforce), Apex полностью запускается по запросу. Платформа Force.com

Последовательность действий

Есть две последовательности действий, когда разработчик сохраняет код и когда конечный пользователь выполняет какое-либо действие, которое вызывает код Apex, как показано ниже:

Действия разработчика

Когда разработчик записывает и сохраняет код Apex на платформе, сервер приложений платформы сначала компилирует код в набор инструкций, понятных интерпретатору среды выполнения Apex, а затем сохраняет эти инструкции как метаданные.

Действия конечного пользователя

Когда конечный пользователь запускает выполнение Apex, щелкая кнопку или открывая страницу Visualforce, сервер приложений платформы извлекает скомпилированные инструкции из метаданных и отправляет их через интерпретатор времени выполнения перед возвратом результата. Конечный пользователь не видит различий во времени выполнения по сравнению со стандартным запросом платформы приложений.

Поскольку Apex является проприетарным языком Salesforce.com, он не поддерживает некоторые функции, которые есть в общем языке программирования. Ниже приведены несколько функций, которые Apex не поддерживает.

  • Он не может отображать элементы в пользовательском интерфейсе.

  • Вы не можете изменить стандартную функциональность, предоставляемую SFDC, а также невозможно предотвратить выполнение стандартной функциональности.

  • Создание нескольких потоков также невозможно, поскольку мы можем сделать это на других языках.

Понимание синтаксиса Apex

Код Apex обычно содержит много вещей, которые нам могут быть знакомы по другим языкам программирования.

Объявление переменной

В качестве строго типизированного языка вы должны объявить каждую переменную с типом данных в Apex. Как видно из приведенного ниже кода (снимок экрана ниже), lstAcc объявлен с типом данных как List of Accounts.

SOQL-запрос

Это будет использоваться для получения данных из базы данных Salesforce. Запрос, показанный на скриншоте ниже, извлекает данные из объекта Account.

Заявление цикла

Этот оператор цикла используется для итерации по списку или итерации по фрагменту кода указанное количество раз. В коде, показанном на скриншоте ниже, итерация будет такой же, как и количество имеющихся у нас записей.

Заявление об управлении потоком

Оператор If используется в этом коде для управления потоком. На основе определенного условия решается, перейти к выполнению или остановить выполнение определенного фрагмента кода. Например, в приведенном ниже коде проверяется, пуст ли список или он содержит записи.

Заявление DML

Выполняет операции вставки, обновления, обновления, обновления и удаления записей в базе данных. Например, приведенный ниже код помогает обновить учетные записи с новым значением поля.

Ниже приведен пример того, как будет выглядеть фрагмент кода Apex. Мы собираемся изучить все эти концепции программирования Apex далее в этом руководстве.

В этой главе мы поймем среду для нашей разработки Salesforce Apex. Предполагается, что у вас уже есть версия Salesforce, настроенная для разработки Apex.

Вы можете разработать код Apex либо в Sandbox, либо в версии Salesforce для разработчиков. Организация "песочница" - это копия вашей организации, в которой вы можете писать код и тестировать его, не рискуя изменить данные или нарушить нормальную функциональность. Согласно стандартной производственной практике, вы должны разработать код в песочнице, а затем развернуть его в производственной среде.

В этом руководстве мы будем использовать версию Salesforce для разработчиков. В версии для разработчиков у вас не будет возможности создать организацию Sandbox. Функции песочницы доступны в других выпусках Salesforce.

Инструменты разработки кода Apex

Во всех редакциях мы можем использовать любой из следующих трех инструментов для разработки кода:

  • Консоль разработчика Force.com
  • Force.com IDE
  • Редактор кода в пользовательском интерфейсе Salesforce

Note − Мы будем использовать консоль разработчика на всем протяжении нашего руководства для выполнения кода, поскольку она проста и удобна для изучения.

Консоль разработчика Force.com

Консоль разработчика - это интегрированная среда разработки с набором инструментов, которые вы можете использовать для создания, отладки и тестирования приложений в вашей организации Salesforce.

Выполните следующие действия, чтобы открыть консоль разработчика -

Step 1 − Перейдите в Name → Developer Console.

Step 2 − Нажмите «Консоль разработчика», и появится окно, как показано на следующем снимке экрана.

Ниже приведены несколько операций, которые можно выполнить с помощью консоли разработчика.

  • Writing and compiling code −Вы можете написать код с помощью редактора исходного кода. Когда вы сохраняете триггер или класс, код автоматически компилируется. Сообщается обо всех ошибках компиляции.

  • Debugging −Вы можете написать код с помощью редактора исходного кода. Когда вы сохраняете триггер или класс, код автоматически компилируется. Сообщается обо всех ошибках компиляции.

  • Testing − Вы можете просматривать журналы отладки и устанавливать контрольные точки, которые помогают в отладке.

  • Checking performance −Вы можете выполнять тесты определенных тестовых классов или всех классов в вашей организации, а также просматривать результаты тестов. Кроме того, вы можете проверить покрытие кода.

  • SOQL queries − Вы можете просмотреть журналы отладки, чтобы найти узкие места в производительности.

  • Color coding and autocomplete − Редактор исходного кода использует цветовую схему для облегчения чтения элементов кода и обеспечивает автоматическое завершение имен классов и методов.

Выполнение кода в консоли разработчика

Все фрагменты кода, упомянутые в этом руководстве, необходимо выполнить в консоли разработчика. Выполните следующие действия, чтобы выполнить действия в консоли разработчика.

Step 1 - Войдите в Salesforce.com, используя login.salesforce.com. Скопируйте фрагменты кода, упомянутые в руководстве. На данный момент мы будем использовать следующий пример кода.

String myString = 'MyString';
System.debug('Value of String Variable'+myString);

Step 2 - Чтобы открыть консоль разработчика, нажмите «Имя» → «Консоль разработчика», а затем нажмите «Выполнить анонимно», как показано ниже.

Step 3 - На этом шаге появится окно, в которое вы можете вставить код.

Step 4 - Когда мы нажимаем на Execute, откроются журналы отладки. Когда журнал появится в окне, как показано ниже, щелкните запись журнала.

Затем введите «ПОЛЬЗОВАТЕЛЬ» в окне, как показано ниже, и оператор вывода появится в окне отладки. Этот оператор USER используется для фильтрации вывода.

Таким образом, вы будете выполнять все вышеупомянутые шаги, чтобы выполнить любой фрагмент кода в этом руководстве.

Пример разработки корпоративного приложения

В нашем руководстве мы будем внедрять CRM-приложение для химической и перерабатывающей компании. Эта компания занимается с поставщиками и предоставляет услуги. Мы будем работать над небольшими фрагментами кода, связанными с этим примером, на протяжении всего руководства, чтобы подробно разобраться в каждой концепции.

Для выполнения кода в этом руководстве вам потребуется создать два объекта: объекты «Клиент» и «Счет-фактура». Если вы уже знаете, как создавать эти объекты в Salesforce, вы можете пропустить шаги, указанные ниже. В противном случае вы можете следовать приведенному ниже пошаговому руководству.

Создание объекта клиента

Сначала мы настроим объект Customer.

Step 1- Перейдите в «Настройка» и найдите «Объект», как показано ниже. Затем щелкните ссылку "Объекты", как показано ниже.

Step 2 - После открытия страницы объекта щелкните значок 'Create New Object', как показано ниже.

Step 3- После нажатия на кнопку появится страница создания нового объекта, на которой необходимо ввести все данные объекта, как указано ниже. Имя объекта должно быть Customer. Вам просто нужно ввести информацию в поле, как показано на скриншоте ниже, и оставить другие параметры по умолчанию как есть.

Введите информацию и нажмите кнопку «Сохранить» -

Выполнив указанные выше действия, мы успешно создали объект «Клиент».

Создание настраиваемых полей для объекта клиента

Теперь, когда у нас настроен объект «Клиент», мы создадим поле «Активный», а затем вы сможете создать другие поля, выполнив аналогичные шаги. Имя и имя API поля будут указаны на скриншоте.

Step 1- Мы будем создавать поле с именем «Активный» типа данных как флажок. Зайдите в Setup и щелкните по нему.

Step 2 - Найдите «Объект», как показано ниже, и щелкните по нему.

Step 3 - Щелкните по объекту «Клиент».

Step 4 - После того, как вы нажали ссылку объекта "Клиент" и откроется страница с подробными сведениями об объекте, нажмите кнопку "Создать".

Step 5 - Теперь выберите тип данных как Checkbox и нажмите Next.

Step 6 - Введите имя поля и метку, как показано ниже.

Step 7 - Щелкните "Видимый", а затем щелкните "Далее".

Step 8 - Теперь нажмите «Сохранить».

Следуя вышеуказанным шагам, создается настраиваемое поле «Активный». Вы должны выполнить все описанные выше шаги по созданию настраиваемых полей для остальных полей. Это окончательный вид объекта клиента после создания всех полей -

Создание объекта счета-фактуры

Step 1 - Перейдите в раздел «Настройка» и найдите «Объект», а затем щелкните ссылку «Объекты», как показано ниже.

Step 2 - После открытия страницы объекта нажмите кнопку «Создать новый объект», как показано ниже.

Step 3- После нажатия на кнопку откроется страница создания нового объекта, как показано на скриншоте ниже. Здесь вам нужно ввести детали. Имя объекта должно быть «Счет-фактура». Это похоже на то, как мы создали объект Customer ранее в этом руководстве.

Step 4 - Введите информацию, как показано ниже, а затем нажмите кнопку «Сохранить».

Следуя этим шагам, ваш объект «Счет-фактура» будет создан.

Создание настраиваемых полей для объекта счета-фактуры

Мы будем создавать поле Описание объекта Invoice, как показано ниже -

Step 1 - Зайдите в Setup и щелкните по нему.

Step 2 - Найдите «Объект», как показано ниже, и щелкните по нему.

Step 3 - Щелкните по объекту «Счет-фактура».

Затем нажмите «Новый».

Step 4 - Выберите тип данных как Text Area и затем нажмите кнопку Next.

Step 5 - Введите информацию, как указано ниже.

Step 6 - Щелкните "Видимый", а затем "Далее".

Step 7 - Щелкните Сохранить.

Точно так же вы можете создать другие поля в объекте «Счет-фактура».

Таким образом, мы создали объекты, необходимые для этого урока. В следующих главах мы будем изучать различные примеры, основанные на этих объектах.

Понимание типов данных

Язык Apex строго типизирован, поэтому каждая переменная в Apex будет объявляться с определенным типом данных. Все переменные вершины изначально инициализируются нулевым значением. Разработчику всегда рекомендуется убедиться, что переменным присвоены правильные значения. В противном случае такие переменные при использовании вызовут исключения с нулевым указателем или любые необработанные исключения.

Apex поддерживает следующие типы данных -

  • Примитив (целое, двойное, длинное, дата, дата и время, строка, идентификатор или логическое значение)

  • Коллекции (списки, наборы и карты) (будет рассмотрено в главе 6)

  • sObject

  • Enums

  • Классы, объекты и интерфейсы (будет рассмотрено в главах 11, 12 и 13)

В этой главе мы рассмотрим все примитивные типы данных, объекты sObject и перечисления. В следующих главах мы рассмотрим Коллекции, Классы, Объекты и Интерфейсы, поскольку они являются ключевыми темами, которые нужно изучать индивидуально.

Примитивные типы данных

В этом разделе мы обсудим примитивные типы данных, поддерживаемые Apex.

Целое число

32-битное число без десятичной точки. Диапазон значений для этого начинается от -2 147 483 648, а максимальное значение - до 2 147 483 647.

Example

Мы хотим объявить переменную, в которой будет храниться количество бочек, которые необходимо отправить покупателю химического завода.

Integer barrelNumbers = 1000;
system.debug(' value of barrelNumbers variable: '+barrelNumbers);

В System.debug() функция печатает значение переменной, чтобы мы могли использовать его для отладки или чтобы узнать, какое значение переменная содержит в настоящее время.

Вставьте приведенный выше код в консоль разработчика и нажмите «Выполнить». Как только журналы будут сгенерированы, в нем будет отображаться значение переменной «BararNumbers» как 1000.

Булево

Эта переменная может иметь значение true, false или null. Часто этот тип переменной можно использовать в качестве флага в программировании, чтобы определить, установлено ли конкретное условие или нет.

Example

Если логическое значение shipmentDispatched должно быть установлено как true, то его можно объявить как -

Boolean shipmentDispatched;
shipmentDispatched = true;
System.debug('Value of shipmentDispatched '+shipmentDispatched);

Свидание

Этот тип переменной указывает дату. Это может хранить только дату, но не время. Чтобы сохранить дату вместе со временем, нам нужно будет сохранить ее в переменной DateTime.

Example

Рассмотрим следующий пример, чтобы понять, как работает переменная Date.

//ShipmentDate can be stored when shipment is dispatched.
Date ShipmentDate = date.today();
System.debug('ShipmentDate '+ShipmentDate);

Долго

Это 64-битное число без десятичной точки. Это используется, когда нам нужен диапазон значений шире, чем предоставленный Integer.

Example

Если выручка компании будет храниться, мы будем использовать тип данных Long.

Long companyRevenue = 21474838973344648L;
system.debug('companyRevenue'+companyRevenue);

Объект

Мы можем назвать это любым типом данных, который поддерживается в Apex. Например, переменная Class может быть объектом этого класса, а общий тип sObject также является объектом, и аналогичный конкретный тип объекта, такой как Account, также является объектом.

Example

Рассмотрим следующий пример, чтобы понять, как работает переменная bject.

Account objAccount = new Account (Name = 'Test Chemical');
system.debug('Account value'+objAccount);

Note - Вы также можете создать объект предопределенного класса, как указано ниже -

//Class Name: MyApexClass
MyApexClass classObj = new MyApexClass();

Это объект класса, который будет использоваться как переменная класса.

Строка

Строка - это любой набор символов в одинарных кавычках. У него нет ограничений на количество символов. Здесь размер кучи будет использоваться для определения количества символов. Это ограничивает монополию программы Apex на ресурсы, а также гарантирует, что она не станет слишком большой.

Example

String companyName = 'Abc International';
System.debug('Value companyName variable'+companyName);

Время

Эта переменная используется для хранения определенного времени. Эту переменную всегда следует объявлять системным статическим методом.

Blob

Blob - это набор двоичных данных, которые хранятся как объект. Это будет использоваться, когда мы хотим сохранить вложение в salesforce в переменной. Этот тип данных преобразует вложения в один объект. Если большой двоичный объект необходимо преобразовать в строку, мы можем использовать для этого методы toString и valueOf.

sObject

Это особый тип данных в Salesforce. Она похожа на таблицу в SQL и содержит поля, похожие на столбцы в SQL. Есть два типа sObject - Standard и Custom.

Например, Account является стандартным sObject, а любой другой определяемый пользователем объект (например, созданный нами объект Customer) - это Custom sObject.

Example

//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

Enum - это абстрактный тип данных, в котором хранится одно значение из конечного набора указанных идентификаторов. Вы можете использовать ключевое слово Enum для определения Enum. Enum можно использовать как любой другой тип данных в Salesforce.

Example

Вы можете объявить возможные названия химического соединения, выполнив следующий код -

//Declaring enum for Chemical Compounds
public enum Compounds {HCL, H2SO4, NACL, HG}
Compounds objC = Compounds.HCL;
System.debug('objC value: '+objC);

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.

Declaring Variables

Вы можете объявить переменные в Apex, например String и Integer, следующим образом:

String strName = 'My String';  //String variable declaration
Integer myInteger = 1;         //Integer variable declaration
Boolean mtBoolean = true;      //Boolean variable declaration

Apex variables are Case-Insensitive

Это означает, что приведенный ниже код вызовет ошибку, поскольку переменная 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');
}

Scope of Variables

Переменная Apex действительна с того момента, когда она объявлена ​​в коде. Поэтому нельзя повторно определять одну и ту же переменную в блоке кода. Кроме того, если вы объявляете какую-либо переменную в методе, тогда область действия этой переменной будет ограничена только этим конкретным методом. Однако доступ к переменным класса можно получить по всему классу.

Example

//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, как и в любом другом языке программирования, представляет собой любой набор символов без ограничения количества символов.

Example

String companyName = 'Abc International';
System.debug('Value companyName variable'+companyName);

Строковые методы

Класс String в Salesforce имеет множество методов. В этой главе мы рассмотрим некоторые из наиболее важных и часто используемых строковых методов.

содержит

Этот метод вернет истину, если данная строка содержит указанную подстроку.

Syntax

public Boolean contains(String substring)

Example

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);

равно

Этот метод вернет истину, если данная строка и строка, переданная в методе, имеют одинаковую двоичную последовательность символов и не равны нулю. Вы также можете сравнить идентификатор записи SFDC, используя этот метод. Этот метод чувствителен к регистру.

Syntax

public Boolean equals(Object string)

Example

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

Этот метод вернет true, если stringtoCompare имеет ту же последовательность символов, что и данная строка. Однако в этом методе регистр не учитывается.

Syntax

public Boolean equalsIgnoreCase(String stringtoCompare)

Example

Следующий код вернет истину, поскольку строковые символы и последовательность совпадают, игнорируя чувствительность к регистру.

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, из данной строки. Это полезно, когда вы хотите удалить некоторые определенные символы из строки и не знаете точный индекс удаляемых символов. Этот метод чувствителен к регистру и не будет работать, если последовательность символов такая же, но регистр другой.

Syntax

public String remove(String stringToRemove)

Example

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, из данной строки, но только если она встречается в конце. Этот метод не чувствителен к регистру.

Syntax

public String removeEndIgnoreCase(String stringToRemove)

Example

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);

начинается с

Этот метод вернет истину, если данная строка начинается с префикса, указанного в методе.

Syntax

public Boolean startsWith(String prefix)

Example

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. Нет никакого логического различия между массивами и списками, поскольку их внутренняя структура данных и методы также совпадают, но синтаксис массива немного традиционный, как Java.

Ниже представлено представление массива продуктов -

Index 0 - HCL

Index 1 - H2SO4

Index 2 - NACL

Index 3 - H2O

Index 4 - N2

Index 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 объявляются с ключевым словом 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. Принятие решений необходимо для управления потоком выполнения, когда выполняется определенное условие или нет. Ниже приводится общая форма типичной структуры принятия решений, встречающейся в большинстве языков программирования.

Sr. No. Заявление и описание
1 если заявление

Оператор if состоит из логического выражения, за которым следует один или несколько операторов.

2 если ... еще заявление

За оператором if может следовать необязательный else оператор, который выполняется, когда логическое выражение ложно.

3 if ... elseif ... else инструкция

За оператором if может следовать необязательный else if...else оператор, который очень полезен для проверки различных условий с помощью одного оператора if ... else if.

4 вложенный оператор if

Вы можете использовать один if or else if заявление внутри другого if or else if заявления).

Циклы используются, когда определенный фрагмент кода должен повторяться с желаемым числом итераций. Apex поддерживает стандартный традиционный цикл for, а также другие расширенные типы циклов. В этой главе мы подробно обсудим циклы в Apex.

Оператор цикла позволяет нам выполнять оператор или группу операторов несколько раз, и ниже приводится общий от оператора цикла в большинстве языков программирования:

В следующих таблицах перечислены различные циклы, которые обрабатывают требования к циклам на языке программирования Apex. Щелкните следующие ссылки, чтобы проверить их детали.

Sr. No. Тип и описание петли
1 для цикла

Этот цикл выполняет набор операторов для каждого элемента в наборе записей.

2 SOQL для цикла

Выполните последовательность операторов непосредственно над возвращенным набором SOQL-запроса.

3 Java-подобный цикл for

Выполните последовательность операторов в традиционном синтаксисе, подобном Java.

4 пока цикл

Повторяет утверждение или группу утверждений, пока выполняется данное условие. Он проверяет условие перед выполнением тела цикла.

5 делать ... пока цикл

Подобен оператору while, за исключением того, что он проверяет условие в конце тела цикла.

Коллекции - это тип переменных, которые могут хранить несколько записей. Например, List может хранить несколько записей объекта Account. Давайте теперь подробно рассмотрим все типы коллекций.

Списки

Список может содержать любое количество записей примитивов, коллекций, объектов sObject, определенных пользователем и встроенных в тип Apex. Это один из наиболее важных типов коллекций, а также у него есть некоторые системные методы, специально предназначенные для использования со списком. Индекс списка всегда начинается с 0. Это синоним массива в Java. Список должен быть объявлен с ключевым словом «Список».

Example

Ниже приведен список, который содержит список примитивного типа данных (строка), то есть список городов.

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>();

Наборы

Набор - это тип коллекции, который содержит несколько неупорядоченных уникальных записей. Набор не может иметь повторяющихся записей. Как и списки, наборы могут быть вложенными.

Example

Мы будем определять набор продуктов, которые продает компания.

Set<string> ProductSet = new Set<string>{'Phenol', 'Benzene', 'H2SO4'};
System.debug('Value of ProductSet'+ProductSet);

Методы для множеств

Set поддерживает методы, которые мы можем использовать при программировании, как показано ниже (мы расширяем приведенный выше пример) -

// 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);

Карты

Это пара "ключ-значение", которая содержит уникальный ключ для каждого значения. И ключ, и значение могут относиться к любому типу данных.

Example

В следующем примере представлена ​​карта названия продукта с кодом продукта.

// 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);

Методы для карт

Ниже приведены несколько примеров, демонстрирующих методы, которые можно использовать с Map.

// 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);

Значения карты могут быть неупорядоченными, поэтому нам не следует полагаться на порядок, в котором значения хранятся, и пытаться получить доступ к карте, всегда используя ключи. Значение карты может быть нулевым. Ключи карты при объявлении String чувствительны к регистру; например, ABC и abc будут рассматриваться как разные ключи и обрабатываться как уникальные.

Что такое класс?

Класс - это шаблон или план, из которого создаются объекты. Объект - это экземпляр класса. Это стандартное определение класса. Классы Apex похожи на классы Java.

Например, InvoiceProcessorclass описывает класс, который имеет все методы и действия, которые могут быть выполнены в Invoice. Если вы создадите экземпляр этого класса, он будет представлять единственную накладную, которая в настоящее время находится в контексте.

Создание классов

Вы можете создать класс в Apex из консоли разработчика, Force.com Eclipse IDE, а также со страницы сведений о классе Apex.

Из консоли разработчика

Выполните следующие действия, чтобы создать класс Apex из консоли разработчика:

Step 1 - Перейдите в «Имя» и нажмите «Консоль разработчика».

Step 2 - Щелкните Файл ⇒ Создать, а затем щелкните класс Apex.

Из Force.com IDE

Выполните следующие действия, чтобы создать класс из Force.com IDE:

Step 1 - Откройте Force.com Eclipse IDE

Step 2 - Создайте новый проект, щелкнув File ⇒ New ⇒ Apex Class.

Step 3 - Укажите имя для класса и нажмите OK.

Как только это будет сделано, будет создан новый класс.

Со страницы сведений о классе Apex

Выполните следующие действия, чтобы создать класс на странице сведений о классе Apex -

Step 1 - Щелкните Имя ⇒ Настройка.

Step 2- Найдите «Apex Class» и щелкните ссылку. Откроется страница сведений о классе Apex.

Step 3 - Нажмите «Новый», затем укажите имя класса и нажмите «Сохранить».

Структура классов Apex

Ниже приведен образец структуры определения класса Apex.

Syntax

private | public | global
[virtual | abstract | with sharing | without sharing]
class ClassName [implements InterfaceNameList] [extends ClassName] {
   // Classs Body
}

В этом определении используется комбинация модификаторов доступа, режимов совместного использования, имени класса и тела класса. Все эти варианты мы рассмотрим дальше.

Example

Ниже приведен образец структуры для определения класса 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;
   }
}

Модификаторы доступа

Частный

Если вы объявите модификатор доступа как «Private», то этот класс будет известен только локально, и вы не сможете получить доступ к этому классу за пределами этой конкретной части. По умолчанию у классов есть этот модификатор.

Общественные

Если вы объявляете класс как «Public», это означает, что этот класс доступен для вашей организации и вашего определенного пространства имен. Обычно с этим ключевым словом определяется большинство классов Apex.

Глобальный

Если вы объявите класс как «глобальный», то он будет доступен для всех кодов вершины независимо от вашей организации. Если у вас есть метод, определенный с помощью ключевого слова веб-службы, вы должны объявить содержащий класс с глобальным ключевым словом.

Режимы совместного использования

Давайте теперь обсудим различные способы обмена.

С обменом

Это особенность классов Apex в Salesforce. Когда класс указан с ключевым словом «With Sharing», это имеет следующие последствия: когда класс будет запущен, он будет уважать настройки доступа пользователя и разрешения профиля. Предположим, действие пользователя вызвало обновление записи для 30 записей, но пользователь имеет доступ только к 20 записям, а 10 записей недоступны. Затем, если класс выполняет действие по обновлению записей, будут обновлены только 20 записей, к которым у пользователя есть доступ, а остальные 10 записей не будут обновлены. Это также называется пользовательским режимом.

Без разглашения

Даже если у пользователя нет доступа к 10 записям из 30, все 30 записей будут обновлены, поскольку класс работает в системном режиме, т. Е. Он был определен с ключевым словом Without Sharing. Это называется системным режимом.

Виртуальный

Если вы используете ключевое слово virtual, это означает, что этот класс может быть расширен и разрешены переопределения. Если методы необходимо переопределить, классы следует объявлять с ключевым словом virtual.

Аннотация

Если вы объявите класс как «абстрактный», он будет содержать только сигнатуру метода, а не фактическую реализацию.

Переменные класса

Syntax

[public | private | protected | global] [final] [static] data_type
variable_name [= value]

В приведенном выше синтаксисе -

  • Тип данных переменной и имя переменной являются обязательными
  • Модификаторы доступа и значения не являются обязательными.

Example

public static final Integer myvalue;

Методы класса

В Apex есть два модификатора для методов класса - Public и Protected. Тип возврата является обязательным для метода, и если метод ничего не возвращает, вы должны указать void в качестве типа возврата. Кроме того, для метода также требуется Body.

Syntax

[public | private | protected | global]
[override]
[static]

return_data_type method_name (input parameters) {
   // Method body goes here
}

Объяснение синтаксиса

Параметры, указанные в квадратных скобках, необязательны. Однако следующие компоненты важны -

  • return_data_type
  • method_name

Модификаторы доступа для методов класса

Используя модификаторы доступа, вы можете указать уровень доступа для методов класса. Например, общедоступный метод будет доступен из любой точки класса и за пределами класса. Приватный метод будет доступен только внутри класса. Global будет доступен для всех классов Apex и может быть представлен как метод веб-службы, доступный другим классам Apex.

Example

//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;
}

Конструкторы классов

Конструктор - это код, который вызывается при создании объекта из схемы класса. Его имя совпадает с именем класса.

Нам не нужно определять конструктор для каждого класса, поскольку по умолчанию вызывается конструктор без аргументов. Конструкторы полезны для инициализации переменных или когда процесс должен быть выполнен во время инициализации класса. Например, вы захотите присвоить некоторым целочисленным переменным значения 0 при вызове класса.

Example

// 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;
   }
}

Вы также можете вызвать метод класса через конструктор. Это может быть полезно при программировании Apex для контроллера визуальной силы. Когда создается объект класса, вызывается конструктор, как показано ниже -

// Class and constructor has been instantiated
MySampleApexClass2 objClass = new MySampleApexClass2();
Double FinalPrice = MySampleApexClass2.getCalculatedValueViaPrice(100);
System.debug('FinalPrice: '+FinalPrice);

Конструкторы перегрузки

Конструкторы могут быть перегружены, т. Е. У класса может быть более одного конструктора, определенного с разными параметрами.

Example

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);

Экземпляр класса называется Object. С точки зрения 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);

sОбъект создание

sObjects - это объекты Salesforce, в которых вы храните данные. Например, «Учетная запись», «Контакт» и т. Д. Являются настраиваемыми объектами. Вы можете создавать экземпляры объектов этих 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);

Static Variable Use

Статические переменные будут созданы только один раз при загрузке класса, и это явление можно использовать, чтобы избежать рекурсии триггера. Значение статической переменной будет одинаковым в одном контексте выполнения, и любой выполняемый класс, триггер или код может ссылаться на него и предотвращать рекурсию.

Интерфейс похож на класс 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;
   }
}

Когда вы реализуете интерфейс, обязательно реализовать метод этого интерфейса. Если вы не реализуете методы интерфейса, это вызовет ошибку. Вам следует использовать интерфейсы, если вы хотите сделать реализацию метода обязательной для разработчика.

Стандартный интерфейс Salesforce для Batch Apex

SFDC действительно имеет стандартные интерфейсы, такие как Database.Batchable, Schedulable и т. Д. Например, если вы реализуете интерфейс Database.Batchable, вы должны реализовать три метода, определенные в интерфейсе - Start, Execute и Finish.

Ниже приведен пример для стандартной базы данных, предоставляемой Salesforce, с возможностью игры в игру, которая отправляет электронные письма пользователям со статусом пакета. Этот интерфейс имеет 3 метода: Start, Execute и Finish. Используя этот интерфейс, мы можем реализовать функциональность Batchable, а также предоставляет переменную BatchableContext, которую мы можем использовать для получения дополнительной информации о выполняемой партии и для выполнения других функций.

global class CustomerProessingBatch implements Database.Batchable<sobject7>,
Schedulable {
   // Add here your email address
   global String [] email = new String[] {'[email protected]'};

   // 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('[email protected]');
      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);

В этой главе мы обсудим, как выполнять различные функции изменения базы данных в Salesforce. Есть две команды, с помощью которых мы можем выполнять функции.

Заявления DML

DML - это действия, которые выполняются для выполнения операций вставки, обновления, удаления, обновления, восстановления записей, слияния записей или преобразования потенциальных клиентов.

DML - одна из наиболее важных частей в Apex, поскольку почти каждый бизнес-сценарий включает изменения и модификации базы данных.

Методы базы данных

Все операции, которые вы можете выполнять с помощью операторов DML, также можно выполнять с помощью методов базы данных. Методы базы данных - это системные методы, которые можно использовать для выполнения операций DML. Методы базы данных обеспечивают большую гибкость по сравнению с операторами DML.

В этой главе мы рассмотрим первый подход с использованием операторов DML. Мы рассмотрим методы базы данных в следующей главе.

Заявления DML

Давайте теперь снова рассмотрим пример компании-поставщика химикатов. В наших записях счетов-фактур есть поля: Статус, Оплаченная сумма, Оставшаяся сумма, Дата следующей оплаты и Номер счета. Счета, которые были созданы сегодня и имеют статус «Ожидание», должны быть обновлены до «Оплачены».

Вставить операцию

Операция вставки используется для создания новых записей в базе данных. Вы можете создавать записи любого стандартного или настраиваемого объекта с помощью оператора Insert DML.

Example

Мы можем создавать новые записи в объекте 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);

Операция обновления

Операция обновления заключается в обновлении существующих записей. В этом примере мы обновим поле «Статус» существующей записи счета-фактуры на «Оплачено».

Example

// 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 используется для выполнения операции обновления, и если обновляемые записи отсутствуют в базе данных, тогда также создаются новые записи.

Example

Предположим, что необходимо обновить записи о клиентах в объекте Customer. Мы обновим существующую запись клиента, если она уже существует, иначе создадим новую. Это будет основано на значении поля APEX_External_Id__c. Это поле будет нашим полем, чтобы определить, присутствуют ли уже записи или нет.

Note - Перед выполнением этого кода создайте запись в объекте Customer со значением поля внешнего идентификатора как «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.

Example

В этом случае мы удалим счета-фактуры, которые были созданы для целей тестирования, то есть те, которые содержат имя «Тест».

Вы также можете выполнить этот фрагмент из консоли разработчика, не создавая класс.

// 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');

Отменить удаление операции

Вы можете отменить удаление записи, которая была удалена и находится в корзине. Все отношения, которые есть у удаленной записи, также будут восстановлены.

Example

Предположим, что записи, удаленные в предыдущем примере, необходимо восстановить. Этого можно добиться на следующем примере. Код в предыдущем примере был изменен для этого примера.

// 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');

Методы класса базы данных - это еще один способ работы с операторами DML, которые более гибки, чем операторы DML, такие как вставка, обновление и т. Д.

Различия между методами базы данных и операторами DML

Заявления DML Методы базы данных
Частичное обновление не допускается. Например, если у вас в списке 20 записей, то будут обновлены либо все записи, либо ни одна. Допускается частичное обновление. Вы можете указать параметр в методе базы данных как true или false, true, чтобы разрешить частичное обновление, и false, чтобы не разрешить то же самое.
Вы не можете получить список успешных и неудачных записей. Вы можете получить список успешных и неудачных записей, как мы видели в примере.
Example - вставить listName Example - 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());
      }
   }
}

Операция обновления

Давайте теперь рассмотрим наш бизнес-пример с использованием методов базы данных. Предположим, нам нужно обновить поле статуса объекта Invoice, но в то же время нам также нужна информация, такая как статус записей, идентификаторы неудачных записей, количество успешных попыток и т. Д. Это невозможно с использованием операторов 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());
      }
   }
}

В этом руководстве мы будем рассматривать только операции Insert и Update. Остальные операции очень похожи на эти операции и на то, что мы делали в предыдущей главе.

Для каждой компании или приложения функция поиска является одним из основных требований. Для этого Salesforce.com предлагает два основных подхода с использованием SOSL и SOQL. Давайте подробно обсудим подход SOSL в этой главе.

SOSL

Поиск текстовой строки по объекту и по полю будет выполняться с помощью SOSL. Это язык поиска объектов Salesforce. Он имеет возможность поиска определенной строки в нескольких объектах.

Операторы SOSL оценивают список sObject, при этом каждый список содержит результаты поиска для определенного типа sObject. Списки результатов всегда возвращаются в том же порядке, в каком они были указаны в запросе SOSL.

Пример запроса SOSL

Рассмотрим бизнес-пример, в котором нам нужно разработать программу, которая может выполнять поиск по указанной строке. Предположим, нам нужно найти строку «ABC» в поле «Имя клиента» объекта «Счет-фактура». Код выглядит следующим образом -

Во-первых, вы должны создать одну запись в объекте Invoice с именем клиента как «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 в следующей главе.

Это язык объектных запросов 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, и, следовательно, у одного 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

Выполните этот фрагмент кода в консоли разработчика. После выполнения скопируйте идентификатор счета-фактуры из консоли разработчика, а затем откройте его в SFDC, как показано ниже. Вы можете видеть, что родительская запись уже назначена записи счета-фактуры, как показано ниже.

Получение дочерних записей

Давайте теперь рассмотрим пример, в котором все счета-фактуры, относящиеся к конкретной записи клиента, должны быть в одном месте. Для этого вы должны знать имя родственного ребенка. Чтобы увидеть имя дочернего отношения, перейдите на страницу сведений о поле дочернего объекта и проверьте значение «Дочернее отношение». В нашем примере это счета-фактуры, к которым в конце добавляется __r.

пример

В этом примере нам нужно будет настроить данные, создать клиента с именем как запись «ABC Customer», а затем добавить 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 Customer», тогда вы можете использовать эту функцию, чтобы получить средний доход.

пример

// 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

Вы можете использовать переменную Apex в запросе SOQL для получения желаемых результатов. На переменные 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 будет применять настройки общего доступа текущего пользователя к коду Apex. Это не требует разрешения профиля, только настройки общего доступа на уровне данных.

Давайте рассмотрим пример, в котором наш пользователь имеет доступ к 5 записям, но общее количество записей равно 10. Поэтому, когда класс Apex будет объявлен с ключевым словом «With Sharing», он вернет только 5 записей, для которых пользователь имеет доступ к.

Example

Во-первых, убедитесь, что вы создали не менее 10 записей в объекте «Клиент» с «Имя» из 5 записей как «Клиент ABC», а остальные 5 записей как «Клиент XYZ». Затем создайте правило совместного использования, которое будет предоставлять «ABC Customer» всем пользователям. Нам также необходимо убедиться, что мы установили OWD объекта Customer как Private.

Вставьте приведенный ниже код в анонимный блок в консоли разработчика.

// 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();

Без передачи ключевого слова

Как следует из названия, класс, объявленный с этим ключевым словом, выполняется в системном режиме, т. Е. Независимо от доступа пользователя к записи, запрос будет извлекать все записи.

// 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 на странице списка классов

Step 1 - В разделе «Настройка» выберите «Разработка» → «Классы Apex».

Step 2- Щелкните имя класса, который вы хотите ограничить. Мы щелкнули по CustomerOperationClass.

Step 3 - Щелкните Безопасность.

Step 4 - Выберите профили, которые вы хотите включить, из списка «Доступные профили» и нажмите «Добавить» или выберите профили, которые вы хотите отключить, из списка «Активированные профили» и нажмите «Удалить».

Step 5 - Щелкните Сохранить.

Настройка безопасности Apex из набора разрешений

Step 1 - В разделе «Настройка» выберите «Управление пользователями» → «Наборы разрешений».

Step 2 - Выберите набор разрешений.

Step 3 - Щелкните Доступ к классу Apex.

Step 4 - Щелкните Edit.

Step 5 - Выберите классы Apex, которые нужно включить, из списка «Доступные классы Apex» и нажмите «Добавить» или выберите классы Apex, которые необходимо отключить, в списке «Включенные классы Apex» и нажмите «Удалить».

Step 6 - Щелкните кнопку Сохранить.

Вызов Apex относится к процессу выполнения класса Apex. Класс Apex может быть выполнен только при его вызове одним из способов, перечисленных ниже:

  • Триггеры и анонимный блок

  • Триггер, вызываемый для указанных событий

  • Асинхронный апекс

  • Планирование запуска класса Apex через определенные интервалы или запуск пакетного задания

  • Класс веб-служб

  • Класс службы электронной почты Apex

  • Веб-службы Apex, которые позволяют раскрывать ваши методы через веб-службы SOAP и REST.

  • Контроллеры Visualforce

  • Служба электронной почты Apex для обработки входящей электронной почты

  • Вызов Apex с помощью JavaScript

  • Набор инструментов Ajax для вызова методов веб-служб, реализованных в Apex

Теперь мы поймем несколько распространенных способов вызова Apex.

От Выполнить анонимный блок

Вы можете вызвать класс Apex, выполнив анонимно в консоли разработчика, как показано ниже -

Step 1 - Откройте консоль разработчика.

Step 2 - Щелкните Debug.

Step 3- Откроется окно «Выполнить анонимный», как показано ниже. Теперь нажмите кнопку «Выполнить» -

Step 4 - Откройте журнал отладки, когда он появится на панели журналов.

Из триггера

Вы также можете вызвать класс Apex из Trigger. Триггеры вызываются при возникновении указанного события, а триггеры могут вызывать класс 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

Класс Apex также можно вызвать со страницы Visualforce. Мы можем указать контроллер или расширение контроллера, и будет вызван указанный класс Apex.

пример

VF Page Code

Apex Class Code (Controller Extension)

Триггеры Apex похожи на хранимые процедуры, которые выполняются при наступлении определенного события. Триггер выполняется до и после того, как событие произошло в записи.

Синтаксис

trigger triggerName on ObjectName (trigger_events) { Trigger_code_block }

Выполнение триггера

Ниже приведены события, по которым мы можем запустить триггер.

  • insert
  • update
  • delete
  • merge
  • upsert
  • undelete

Пример триггера 1

Предположим, мы получили бизнес-требование о том, что нам необходимо создать запись счета-фактуры, когда поле «Статус клиента» меняется с «Активно» на «Неактивно». Для этого мы создадим триггер для объекта APEX_Customer__c, выполнив следующие шаги:

Step 1 - Перейти к sObject

Step 2 - Нажмите "Клиент"

Step 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- Это переменная контекста, в которой хранятся записи, которые в данный момент находятся в контексте триггера, которые либо вставляются, либо обновляются. В этом случае эта переменная содержит обновленные записи объекта «Клиент».

В контексте доступны и другие контекстные переменные - trigger.old, trigger.newMap, trigger.OldMap.

Пример запуска 2

Вышеупомянутый триггер будет выполняться, когда есть операция обновления для записей клиента. Предположим, запись счета-фактуры необходимо вставлять только тогда, когда Статус клиента меняется с Неактивный на Активный, а не каждый раз; для этого мы можем использовать другую переменную контекстаtrigger.oldMap который будет хранить ключ как идентификатор записи и значение как старые значения записи.

// 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, которая, как объяснялось ранее, является контекстной переменной, в которой хранятся идентификатор и старое значение обновляемых записей.

Шаблоны проектирования используются, чтобы сделать наш код более эффективным и избежать выхода за пределы регулятора. Часто разработчики могут написать неэффективный код, который может вызвать повторное создание экземпляров объектов. Это может привести к неэффективному, плохо работающему коду и потенциально к нарушению ограничений регулятора. Чаще всего это происходит в триггерах, поскольку они могут работать с набором записей.

В этой главе мы увидим некоторые важные стратегии шаблонов проектирования.

Шаблоны проектирования массовых триггеров

В реальном экономическом случае вам может потребоваться обработать тысячи записей за один раз. Если ваш триггер не предназначен для обработки таких ситуаций, он может дать сбой при обработке записей. Есть несколько передовых методов, которым нужно следовать при реализации триггеров. Все триггеры по умолчанию являются массовыми и могут обрабатывать несколько записей одновременно. Вы всегда должны планировать обработку более одной записи за раз.

Рассмотрим бизнес-пример, в котором вам нужно обработать большое количество записей и вы написали триггер, как показано ниже. Это тот же пример, который мы использовали для вставки записи счета-фактуры, когда Статус клиента изменяется с Неактивно на Активный.

// 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 был написан для блока цикла, который будет работать при обработке только нескольких записей, но когда вы обрабатываете несколько сотен записей, он достигнет предела оператора DML на транзакцию, который является governor limit. Мы подробно рассмотрим ограничения регулятора в следующей главе.

Чтобы этого избежать, мы должны сделать триггер эффективным для одновременной обработки нескольких записей.

Следующий пример поможет вам понять то же самое -

// 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.

Класс Trigger Helper

Написание всего кода в триггере также не является хорошей практикой. Следовательно, вы должны вызвать класс Apex и делегировать обработку от Trigger классу Apex, как показано ниже. Класс Trigger Helper - это класс, который выполняет всю обработку для триггера.

Давайте еще раз рассмотрим наш пример создания записи счета.

// 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
   }
}

Ограничения на выполнение регулятора обеспечивают эффективное использование ресурсов на мультитенантной платформе Force.com. Это предел, установленный Salesforce.com на выполнение кода для эффективной обработки.

Что такое ограничения губернатора?

Как мы знаем, Apex работает в многопользовательской среде, т. Е. Единый ресурс используется всеми клиентами и организациями. Таким образом, необходимо убедиться, что никто не монополизирует ресурсы, и, следовательно, Salesforce.com создал набор ограничений, которые регулируют и ограничивают выполнение кода. Всякий раз, когда любой из ограничений регулятора нарушается, он выдает ошибку и останавливает выполнение программы.

С точки зрения разработчика важно убедиться, что наш код должен быть масштабируемым и не выходить за пределы.

Все эти ограничения применяются для каждой транзакции. Выполнение одного триггера - это одна транзакция.

Как мы видели, шаблон проектирования триггера помогает избежать предельной ошибки. Теперь мы увидим другие важные ограничения.

Как избежать ограничения запросов SOQL

Вы можете выдавать только 100 запросов на транзакцию, то есть, когда ваш код выдаст более 100 запросов SOQL, он выдаст ошибку.

пример

В этом примере показано, как можно достичь предела запросов SOQL -

Следующий триггер перебирает список клиентов и обновляет описание дочерней записи (Invoice) строкой «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. Чтобы избежать этого, никогда не пишите запросы SOQL в цикле For Loop. В этом случае запрос SOQL был написан в цикле For.

Ниже приведен пример, который покажет, как избежать ограничения DML и SOQL. Мы использовали вложенный запрос отношений для получения записей счетов и использовали переменную контекстаtrigger.newMap чтобы получить карту идентификаторов и записей клиентов.

// 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

В этом примере показан массовый триггер вместе с шаблоном вспомогательного класса триггера. Вы должны сначала сохранить вспомогательный класс, а затем сохранить триггер.

Note - Вставьте приведенный ниже код в класс 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 МБ / 12 МБ
Общее количество выданных операторов DML 150
Общее количество записей, полученных одним запросом SOSL 2000 г.
Общее количество отправленных запросов SOSL 20
Общее количество записей, полученных Database.getQueryLocator 10000
Общее количество записей, полученных запросами SOQL 50000

В этой главе мы разберемся с пакетной обработкой в ​​Apex. Рассмотрим сценарий, при котором мы будем обрабатывать большое количество записей ежедневно, возможно, очищая данные или, возможно, удаляя некоторые неиспользуемые данные.

Что такое Batch Apex?

Пакетная обработка Apex - это асинхронное выполнение кода Apex, специально разработанное для обработки большого количества записей и обладающее большей гибкостью в ограничениях регулятора, чем синхронный код.

Когда использовать Batch Apex?

  • Если вы хотите обрабатывать большое количество записей ежедневно или даже в определенный промежуток времени, вы можете выбрать Batch Apex.

  • Кроме того, если вы хотите, чтобы операция была асинхронной, вы можете реализовать Batch Apex. Пакетная Apex представлена ​​как интерфейс, который должен быть реализован разработчиком. Пакетные задания можно запускать программно во время выполнения с помощью Apex. Пакетная обработка Apex работает с небольшими пакетами записей, охватывая весь ваш набор записей и разбивая обработку на управляемые фрагменты данных.

Использование Batch Apex

Когда мы используем Batch Apex, мы должны реализовать предоставленный Salesforce интерфейс Database.Batchable, а затем программно вызвать класс.

Вы можете отслеживать класс, выполнив следующие действия:

Чтобы отслеживать или останавливать выполнение пакетного задания Apex Batch, выберите «Настройка» → «Мониторинг» → «Задания Apex» или «Задания» → «Задания Apex».

Интерфейс Database.Batchable имеет следующие три метода, которые необходимо реализовать:

  • Start
  • Execute
  • Finish

Давайте теперь разберемся с каждым методом подробно.

Начало

Метод Start - один из трех методов интерфейса Database.Batchable.

Syntax

global void execute(Database.BatchableContext BC, list<sobject<) {}

Этот метод вызывается при запуске пакетного задания и собирает данные, с которыми будет работать пакетное задание.

Рассмотрим следующие моменты, чтобы понять метод -

  • Использовать Database.QueryLocatorobject, когда вы используете простой запрос для создания области объектов, используемых в пакетном задании. В этом случае ограничение на количество строк данных SOQL будет обойдено.

  • Используйте итеративный объект, когда у вас есть сложные критерии для обработки записей. Database.QueryLocator определяет объем записей, которые должны быть обработаны.

Выполнить

Давайте теперь разберемся с методом Execute интерфейса Database.Batchable.

Syntax

global void execute(Database.BatchableContext BC, list<sobject<) {}

где list <sObject <возвращается методом Database.QueryLocator.

Этот метод вызывается после метода Start и выполняет всю обработку, необходимую для пакетного задания.

Конец

Теперь мы обсудим метод Finish интерфейса Database.Batchable.

Syntax

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[] {'[email protected]'};
   // 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('[email protected]'); // 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);

Как только этот класс будет выполнен, проверьте указанный вами адрес электронной почты, на который вы получите электронное письмо с информацией. Кроме того, вы можете проверить статус пакетного задания на странице «Мониторинг» и выполнить указанные выше действия.

Если вы проверите журналы отладки, вы можете найти размер списка, который указывает, сколько записей было обработано.

Limitations

Мы можем обрабатывать только 5 пакетных заданий одновременно. Это одно из ограничений Batch Apex.

Планирование пакетного задания Apex с помощью страницы сведений о Apex

Вы можете запланировать класс Apex на странице сведений о Apex, как показано ниже -

Step 1 - Перейдите в «Настройка» ⇒ «Классы Apex», нажмите «Классы Apex».

Step 2 - Щелкните кнопку Schedule Apex.

Step 3 - Сообщите подробности.

Планирование пакетного задания Apex с помощью настраиваемого интерфейса

Вы можете запланировать пакетное задание Apex с помощью настраиваемого интерфейса, как показано ниже -

// Batch Job for Processing the Records
global class CustomerProessingBatch implements Database.Batchable<sobject> {
   global String [] email = new String[] {'[email protected]'};
   // 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('[email protected]');//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 есть определенные инструменты, которые можно использовать для отладки. Одним из них является метод system.debug (), который печатает значение и вывод переменной в журналах отладки.

Мы можем использовать следующие два инструмента для отладки -

  • Консоль разработчика
  • Отчет об ошибках

Отладка через консоль разработчика

Вы можете использовать консоль разработчика и выполнять анонимные функции для отладки Apex, как показано ниже:

Example

Рассмотрим наш существующий пример получения записей о клиентах, которые были созданы сегодня. Мы просто хотим знать, возвращает ли запрос результаты или нет, и если да, то мы проверим значение List.

Вставьте приведенный ниже код в анонимное окно выполнения и следуйте шагам, которые мы сделали для открытия анонимного окна выполнения.

Step 1 - Откройте консоль разработчика.

Step 2 - Откройте Execute anonymous из «Debug», как показано ниже.

Step 3 - Откройте окно «Выполнить анонимно», вставьте следующий код и нажмите «Выполнить».

// 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

Step 4 - Откройте журналы, как показано ниже.

Step 5 - Введите «ПОЛЬЗОВАТЕЛЬ» в условиях фильтрации, как показано ниже.

Step 6 - Откройте USER DEBUG Statement, как показано ниже.

Отладка через журналы отладки

Вы также можете отлаживать тот же класс через журналы отладки. Предположим, у вас есть триггер в объекте Customer, и его нужно отладить для некоторых значений переменных, тогда вы можете сделать это через журналы отладки, как показано ниже -

Это код триггера, который обновляет поле Описание, если измененный клиент активен и вы хотите проверить значения переменных и записей, которые в настоящее время находятся в области видимости -

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);
      }
   }
}

Следуйте инструкциям ниже, чтобы создать журналы отладки.

Step 1- Установите журналы отладки для вашего пользователя. Перейдите в «Настройка» и введите «Журнал отладки» в окне настройки поиска, а затем нажмите «Ссылка».

Step 2 - Установите журналы отладки следующим образом.

Step 3- Введите имя пользователя, который требует настройки. Введите свое имя здесь.

Step 4 - Измените записи клиентов, когда должно произойти событие, чтобы создать журнал отладки.

Step 5- Теперь снова перейдите в раздел журналов отладки. Откройте журналы отладки и нажмите «Сброс».

Step 6 - Щелкните ссылку просмотра первого журнала отладки.

Step 7 - Найдите строку «USER», используя поиск в браузере, как показано ниже.

Оператор отладки покажет значение поля, в котором мы установили точку.

Тестирование - это неотъемлемая часть 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 ()

Этот метод проверяет желаемый результат с фактическим. В этом случае мы ожидаем, что будет вставлена ​​запись Invoice, поэтому мы добавили assert, чтобы проверить то же самое.

Example

/**
* 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
   }
}

Запуск тестового класса

Следуйте инструкциям ниже, чтобы запустить тестовый класс -

Step 1 - Перейдите в классы Apex ⇒ щелкните имя класса «CustomerTriggerTestClass».

Step 2 - Нажмите кнопку «Выполнить тест», как показано.

Step 3 - Проверить статус

Step 4 - Теперь проверьте класс и триггер, для которого мы написали тест.

Класс

Спусковой крючок

Наше тестирование прошло успешно.

Что такое развертывание в SFDC?

До сих пор мы разрабатывали код в Developer Edition, но в реальном сценарии эту разработку необходимо выполнять в песочнице, а затем вам может потребоваться развернуть ее в другой песочнице или производственной среде, и это называется развертыванием. Короче говоря, это перемещение метаданных из одной организации в другую. Причина в том, что вы не можете разработать Apex в производственной организации Salesforce. Живые пользователи, получающие доступ к системе во время разработки, могут дестабилизировать ваши данные или повредить ваше приложение.

Инструменты, доступные для развертывания -

  • Force.com IDE
  • Изменить наборы
  • SOAP API
  • Инструмент миграции Force.com

Поскольку мы используем Developer Edition для нашей разработки и обучения, мы не можем использовать Change Set или другие инструменты, для которых требуется SFDC Enterprise или другая платная версия. Следовательно, в этом руководстве мы будем разрабатывать метод развертывания Force.com IDE.

Force.com Eclipse IDE

Step 1 - Откройте Eclipse и откройте триггер класса, который необходимо развернуть.

Step 2 - После того, как вы нажмете «Развернуть на сервер», введите имя пользователя и пароль организации, в которой необходимо развернуть Компонент.

Выполнив вышеупомянутые шаги, ваши компоненты Apex будут развернуты в целевой организации.

Развертывание с использованием набора изменений

Вы можете развернуть правила проверки, правила рабочего процесса, классы Apex и триггер из одной организации в другую, подключив их с помощью параметров развертывания. В этом случае организации должны быть подключены.

Чтобы открыть настройку развертывания, выполните действия, указанные ниже. Помните, что эта функция недоступна в Developer Edition -

Step 1 - Перейдите в раздел «Настройка» и найдите «Развернуть».

Step 2 - Щелкните «Outbound Change Set», чтобы создать набор изменений для развертывания.

Step 3 - Добавьте компоненты для изменения набора с помощью кнопки «Добавить», затем «Сохранить» и нажмите «Загрузить».

Step 4 - Перейдите в целевую организацию, щелкните набор входящих изменений и, наконец, щелкните развертывание.

Вызовы SOAP API для развертывания

Мы просто сделаем небольшой обзор этого метода, так как это не часто используемый метод.

Вы можете использовать приведенные ниже вызовы методов для развертывания ваших метаданных.

  • compileAndTest()
  • compileClasses()
  • compileTriggers()

Инструмент миграции Force.com

Этот инструмент используется для развертывания по сценарию. Вам необходимо загрузить инструмент Force.com Migration и затем выполнить развертывание на основе файлов. Вы можете загрузить инструмент миграции Force.com, а затем выполнить развертывание по сценарию.