Учебники

Апекс — Краткое руководство

Апекс — Обзор

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

Он имеет Java-подобный синтаксис и действует как хранимые процедуры базы данных. Он позволяет разработчикам добавлять бизнес-логику к большинству системных событий, включая нажатия кнопок, обновления связанных записей и страницы Visualforce. Код Apex может быть инициирован запросами веб-службы и триггерами на объектах. Apex входит в состав Performance Edition, Unlimited Edition, Enterprise Edition и Developer Edition.

Сценарий выполнения кода Apex

Особенности Apex как языка

Давайте теперь обсудим особенности Apex как языка —

интегрированный

Apex имеет встроенную поддержку операций DML, таких как INSERT, UPDATE, DELETE, а также обработку исключений DML. Он поддерживает встроенную обработку запросов SOQL и SOSL, которая возвращает набор записей sObject. Мы будем подробно изучать sObject, SOQL, SOSL в следующих главах.

Java как синтаксис и прост в использовании

Apex прост в использовании, так как он использует синтаксис, такой как Java. Например, объявление переменной, синтаксис цикла и условные операторы.

Сильно интегрированы с данными

Apex ориентирован на данные и предназначен для одновременного выполнения нескольких запросов и операторов DML. Он выдает несколько операторов транзакций в базе данных.

Сильно Типизированный

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

Мультитенантная среда

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

Обновления автоматически

Apex обновляется как часть релизов Salesforce. Нам не нужно обновлять его вручную.

Простое тестирование

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

Когда разработчик должен выбрать Apex?

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

Апекс Приложения

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Apex Компиляция Apex Code

Поток действий

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

SOQL Query

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

Loop Statement

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

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

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

DML заявление

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

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

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

Апекс — Окружающая среда

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

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

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

Процесс развертывания

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

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

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

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

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

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

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

Шаг 1 — Перейдите в Имя → Консоль разработчика

Открытие консоли разработчика Шаг 1

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

Открытие консоли разработчика Step_2

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

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

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

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

  • Проверка производительности — вы можете выполнять тесты определенных классов тестов или всех классов в вашей организации, а также просматривать результаты тестов. Также вы можете проверить покрытие кода.

  • SOQL-запросы. Вы можете просматривать журналы отладки для выявления узких мест производительности.

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

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

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

Тестирование — вы можете просматривать журналы отладки и устанавливать контрольные точки, которые помогают в отладке.

Проверка производительности — вы можете выполнять тесты определенных классов тестов или всех классов в вашей организации, а также просматривать результаты тестов. Также вы можете проверить покрытие кода.

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

Цветовое кодирование и автозаполнение . Редактор исходного кода использует цветовую схему для удобства чтения элементов кода и обеспечивает автозаполнение имен классов и методов.

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

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

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

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

Экран входа

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

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

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

Шаг 3 — На этом шаге появится окно, и вы можете вставить туда код.

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

Шаг 4 — Когда мы нажмем Выполнить , откроются журналы отладки. Как только журнал появится в окне, как показано ниже, нажмите на запись журнала.

Запись журнала

Затем введите «USER» в окне, как показано ниже, и оператор вывода появится в окне отладки. Этот оператор USER используется для фильтрации выходных данных.

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

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

Апекс — Пример

Пример разработки корпоративных приложений

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

Для выполнения кода в этом руководстве вам нужно создать два объекта: объекты Customer и Invoice. Если вы уже знаете, как создавать эти объекты в Salesforce, вы можете пропустить шаги, указанные ниже. Иначе, вы можете следовать пошаговой инструкции ниже.

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

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

Шаг 1 — Перейдите в Setup и затем найдите «Object», как показано ниже. Затем нажмите на ссылку «Объекты», как показано ниже.

Клиентский объект Ceation Step1

Клиентский объект Ceation Step1-2

Шаг 2 — Как только страница объекта открыта, нажмите кнопку « Создать новый объект », как показано ниже.

Клиентский объект Ceation Step3

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

Клиентский объект Ceation Step4

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

Клиентский объект Ceation Step5

Выполнив вышеуказанные шаги, мы успешно создали объект Customer.

Создание пользовательских полей для объекта Customer

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

Шаг 1 — Мы будем создавать поле с именем «Active» типа данных как Checkbox. Зайдите в настройки и нажмите на него.

Создание пользовательского поля клиента Шаг 1

Шаг 2 — Найдите «Объект», как показано ниже, и нажмите на него.

Создание пользовательского поля клиента Step2

Шаг 3 — Нажмите на объект «Клиент».

Создание пользовательского поля клиента Шаг 3

Шаг 4 — После того, как вы нажали на ссылку объекта Customer и появится страница с подробным описанием объекта, нажмите кнопку New.

Создание пользовательского поля клиента Step4

Шаг 5 — Теперь выберите тип данных как флажок и нажмите Далее.

Создание пользовательского поля клиента Step5

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

Создание пользовательского поля клиента Step6

Шаг 7 — Нажмите Visible, а затем нажмите Next.

Создание пользовательского поля клиента Step7

Шаг 8 — Теперь нажмите «Сохранить».

Создание пользовательского поля клиента Step8

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

Финальный вид объекта клиента

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

Шаг 1 — Зайдите в Setup и найдите «Object», а затем нажмите на ссылку «Objects», как показано ниже.

Создание объекта счета Шаг 1

Создание объекта счета Шаг 2

Шаг 2 — Как только страница объекта открыта, нажмите кнопку «Создать новый объект», как показано ниже.

Создание объекта счета Шаг 3

Шаг 3 — После нажатия на кнопку появится новая страница создания объекта, как показано на скриншоте ниже. Вам необходимо ввести детали здесь. Имя объекта должно быть Invoice. Это похоже на то, как мы создали объект Customer ранее в этом уроке.

Создание объекта счета Шаг 4

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

Создание объекта счета Шаг 5

Следуя этим шагам, ваш объект Invoice будет создан.

Создание пользовательских полей для объекта Invoice

Мы создадим поле Description для объекта Invoice, как показано ниже —

Шаг 1 — Зайдите в Setup и нажмите на него.

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

Шаг 2 — Найдите «Объект», как показано ниже, и нажмите на него.

Создание объекта клиента Шаг 1-2

Шаг 3 — Нажмите на объект «Счет».

Создание настраиваемого поля счета Шаг 3

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

Шаг создания настраиваемого поля счета

Шаг 4 — Выберите тип данных как текстовую область и нажмите кнопку «Далее».

Создание настраиваемого поля счета Шаг 5

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

Создание настраиваемого поля счета Шаг 6

Шаг 6 — Нажмите Видимый, а затем Далее.

Создание настраиваемого поля счета Шаг 7

Шаг 7 — Нажмите на Сохранить.

Создание настраиваемого поля счета Шаг 8

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

Окончательный вид объекта счета

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

Апекс — Типы данных

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

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

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

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

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

  • SObject

  • Перечисления

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

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

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

SObject

Перечисления

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

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

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

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

целое число

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

пример

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

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

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

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

логический

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

пример

Если Boolean shipmentDispatched должен быть установлен как true, то он может быть объявлен как —

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

Дата

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

пример

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

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

Долго

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

пример

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

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

объект

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

пример

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

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

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

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

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

строка

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

пример

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

Время

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

капля

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

SObject

Это специальный тип данных в Salesforce. Он похож на таблицу в SQL и содержит поля, похожие на столбцы в SQL. Существует два типа объектов sObject: стандартный и пользовательский.

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

пример

//Declaring an sObject variable of type Account
Account objAccount = new Account();

//Assignment of values to fields of sObjects
objAccount.Name = 'ABC Customer';
objAccount.Description = 'Test Account';
System.debug('objAccount variable value'+objAccount);

//Declaring an sObject for custom object APEX_Invoice_c
APEX_Customer_c objCustomer = new APEX_Customer_c();

//Assigning value to fields
objCustomer.APEX_Customer_Decscription_c = 'Test Customer';
System.debug('value objCustomer'+objCustomer);

Enum

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

пример

Вы можете объявить возможные имена Chemical Compound, выполнив следующий код —

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

Объявление переменных

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

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

Переменные Apex нечувствительны к регистру

Это означает, что приведенный ниже код выдаст ошибку, поскольку переменная ‘m’ была объявлена ​​два раза, и оба будут рассматриваться как одинаковые.

Integer m = 100;
for (Integer i = 0; i<10; i++) {
   integer m = 1; //This statement will throw an error as m is being declared
   again
   System.debug('This code will throw error');
}

Область действия переменных

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

пример

//Declare variable Products
List<string> Products = new List<strings>();
Products.add('HCL');

//You cannot declare this variable in this code clock or sub code block again
//If you do so then it will throw the error as the previous variable in scope
//Below statement will throw error if declared in same code block
List<string> Products = new List<strings>();

Апекс — Струны

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

пример

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

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

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

содержит

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

Синтаксис

public Boolean contains(String substring)

пример

String myProductName1 = 'HCL';
String myProductName2 = 'NAHCL';
Boolean result = myProductName2.contains(myProductName1);
System.debug('O/p will be true as it contains the String and Output is:'+result);

равняется

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

Синтаксис

public Boolean equals(Object string)

пример

String myString1 = 'MyString';
String myString2 = 'MyString';
Boolean result = myString2.equals(myString1);
System.debug('Value of Result will be true as they are same and Result is:'+result);

equalsIgnoreCase

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

Синтаксис

public Boolean equalsIgnoreCase(String stringtoCompare)

пример

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

String myString1 = 'MySTRING';
String myString2 = 'MyString';
Boolean result = myString2.equalsIgnoreCase(myString1);
System.debug('Value of Result will be true as they are same and Result is:'+result);

Удалить

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

Синтаксис

public String remove(String stringToRemove)

пример

String myString1 = 'This Is MyString Example';
String stringToRemove = 'MyString';
String result = myString1.remove(stringToRemove);
System.debug('Value of Result will be 'This Is Example' as we have removed the MyString 
   and Result is :'+result);

removeEndIgnoreCase

Этот метод удаляет строку, указанную в stringToRemove, из заданной строки, но только если она встречается в конце. Этот метод не чувствителен к регистру.

Синтаксис

public String removeEndIgnoreCase(String stringToRemove)

пример

String myString1 = 'This Is MyString EXAMPLE';
String stringToRemove = 'Example';
String result = myString1.removeEndIgnoreCase(stringToRemove);
System.debug('Value of Result will be 'This Is MyString' as we have removed the 'Example'
   and Result is :'+result);

начинается с

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

Синтаксис

public Boolean startsWith(String prefix)

пример

String myString1 = 'This Is MyString EXAMPLE';
String prefix = 'This';
Boolean result = myString1.startsWith(prefix);
System.debug(' This will return true as our String starts with string 'This' and the 
   Result is :'+result);

Апекс — Массивы

Массивы в Apex в основном совпадают со списками в Apex. Нет логического различия между массивами и списками, так как их внутренняя структура данных и методы также одинаковы, но синтаксис массива немного традиционен, как Java.

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

Индекс 0 — HCL

Индекс 1 — H2SO4

Индекс 2 — NACL

Индекс 3 — H2O

Индекс 4 — N2

Индекс 5 — U296

Синтаксис

<String> [] arrayOfProducts = new List<String>();

пример

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

//Defining array
String [] arrayOfProducts = new List<String>();

//Adding elements in Array
arrayOfProducts.add('HCL');
arrayOfProducts.add('H2SO4');
arrayOfProducts.add('NACL');
arrayOfProducts.add('H2O');
arrayOfProducts.add('N2');
arrayOfProducts.add('U296');

for (Integer i = 0; i<arrayOfProducts.size(); i++) {
   //This loop will print all the elements in array
   system.debug('Values In Array: '+arrayOfProducts[i]);
}

Доступ к элементу массива с помощью индекса

Вы можете получить доступ к любому элементу в массиве, используя индекс, как показано ниже —

//Accessing the element in array
//We would access the element at Index 3
System.debug('Value at Index 3 is :'+arrayOfProducts[3]);

Апекс — Константы

Как и в любом другом языке программирования, константы — это переменные, которые не меняют свое значение после объявления или присвоения значения.

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

пример

Рассмотрим класс CustomerOperationClass и постоянную переменную normalCustomerDiscount внутри него —

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

3 if … elseif … else заявление

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

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

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

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

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

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

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

Апекс — Петли

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

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

Петлевая архитектура

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

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

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

2 SOQL для цикла

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

3 Java-как для цикла

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

4 в то время как цикл

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

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

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

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

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

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

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

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

Апекс — Коллекции

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

Списки

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

пример

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

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

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

Методы для списков

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

Ниже приведены некоторые наиболее часто используемые методы —

  • размер()
  • добавлять()
  • получить()
  • Чисто()
  • задавать()

Следующий пример демонстрирует использование всех этих методов

// Initialize the List
List<string> ListOfStatesMethod = new List<string>();

// This statement would give null as output in Debug logs
System.debug('Value of List'+ ListOfStatesMethod);

// Add element to the list using add method
ListOfStatesMethod.add('New York');
ListOfStatesMethod.add('Ohio');

// This statement would give New York and Ohio as output in Debug logs
System.debug('Value of List with new States'+ ListOfStatesMethod);

// Get the element at the index 0
String StateAtFirstPosition = ListOfStatesMethod.get(0);

// This statement would give New York as output in Debug log
System.debug('Value of List at First Position'+ StateAtFirstPosition);

// set the element at 1 position
ListOfStatesMethod.set(0, 'LA');

// This statement would give output in Debug log
System.debug('Value of List with element set at First Position' + ListOfStatesMethod[0]);

// Remove all the elements in List
ListOfStatesMethod.clear();

// This statement would give output in Debug log
System.debug('Value of List'+ ListOfStatesMethod);

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

String [] ListOfStates = new List<string>();

наборы

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

пример

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

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

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

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

Карты

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

пример

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

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

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

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

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

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

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

Шаг 1 — Перейдите в Name и нажмите на консоль разработчика.

Шаг 2 — Нажмите Файл ⇒ Создать, а затем нажмите на класс Apex.

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

Из Force.com IDE

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

Шаг 1 — Откройте Force.com Eclipse IDE

Шаг 2 — Создайте новый проект, нажав Файл ⇒ Новый ⇒ Apex Class.

Шаг 3 — Введите имя для класса и нажмите «ОК».

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

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

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

Шаг 1 — Нажмите на Имя ⇒ Настройка.

Шаг 2 — Найдите «Apex Class» и нажмите на ссылку. Откроется страница сведений о классе Apex.

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

Шаг 3 — Нажмите «Создать», затем укажите имя для класса и нажмите «Сохранить».

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

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

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

Синтаксис

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

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

пример

Ниже приведен пример структуры для определения класса Apex:

public class MySampleApexClass {       //Class definition and body
   public static Integer myValue = 0;  //Class Member variable
   public static String myString = ''; //Class Member variable
   
   public static Integer getCalculatedValue () {
   // Method definition and body
   // do some calculation
      myValue = myValue+10;
      return myValue;
   }
}

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

Частный

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

общественного

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

Глобальный

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

Режимы обмена

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

С обменом

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

Без обмена

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

виртуальный

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

Аннотация

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

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

Синтаксис

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

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

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

пример

public static final Integer myvalue;

Апекс — Методы

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

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

Синтаксис

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

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

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

Эти параметры, указанные в квадратных скобках, являются необязательными. Тем не менее, следующие компоненты имеют важное значение —

  • return_data_type
  • method_name

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

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

пример

//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, когда класс вызывается.

пример

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

Перегрузка Конструкторов

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

пример

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

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

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

Использование статических переменных

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

Apex — Интерфейсы

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

Интерфейсы используются главным образом для обеспечения уровня абстракции для вашего кода. Они отделяют реализацию от объявления метода.

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

Мы создадим интерфейс под названием DiscountProcessor .

// Interface
public interface DiscountProcessor {
   Double percentageDiscountTobeApplied(); // method signature only
}

// Premium Customer Class
public class PremiumCustomer implements DiscountProcessor {
   
   //Method Call
   public Double percentageDiscountTobeApplied () {
      
      // For Premium customer, discount should be 30%
      return 0.30;
   }
}

// Normal Customer Class
public class NormalCustomer implements DiscountProcessor {
   
   // Method Call
   public Double percentageDiscountTobeApplied () {
      
      // For Premium customer, discount should be 10%
      return 0.10;
   }
}

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

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

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

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

global class CustomerProessingBatch implements Database.Batchable<sobject7>,
Schedulable {
   // Add here your email address
   global String [] email = new String[] {'[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);

Апекс — DML

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

DML заявления

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

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

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

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

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

DML заявления

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

Операция вставки

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

пример

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

// fetch the invoices created today, Note, you must have at least one invoice 
// created today

List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c,
   createdDate FROM APEX_Invoice__c WHERE createdDate = today];

// create List to hold the updated invoice records
List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>();
APEX_Customer__c objCust = new APEX_Customer__C();
objCust.Name = 'Test ABC';

//DML for Inserting the new Customer Records
insert objCust;
for (APEX_Invoice__c objInvoice: invoiceList) {
   if (objInvoice.APEX_Status__c == 'Pending') {
      objInvoice.APEX_Status__c = 'Paid';
      updatedInvoiceList.add(objInvoice);
   }
}

// DML Statement to update the invoice status
update updatedInvoiceList;

// Prints the value of updated invoices
System.debug('List has been updated and updated values are' + updatedInvoiceList);

// Inserting the New Records using insert DML statement
APEX_Invoice__c objNewInvoice = new APEX_Invoice__c();
objNewInvoice.APEX_Status__c = 'Pending';
objNewInvoice.APEX_Amount_Paid__c = 1000;
objNewInvoice.APEX_Customer__c = objCust.id;

// DML which is creating the new Invoice record which will be linked with newly
// created Customer record
insert objNewInvoice;
System.debug('New Invoice Id is '+objNewInvoice.id+' and the Invoice Number is'
   + objNewInvoice.Name);

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

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

пример

// Update Statement Example for updating the invoice status. You have to create
and Invoice records before executing this code. This program is updating the
record which is at index 0th position of the List.

// First, fetch the invoice created today
List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c,
createdDate FROM APEX_Invoice__c];
List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>();

// Update the first record in the List
invoiceList[0].APEX_Status__c = 'Pending';
updatedInvoiceList.add(invoiceList[0]);

// DML Statement to update the invoice status
update updatedInvoiceList;

// Prints the value of updated invoices
System.debug('List has been updated and updated values of records are' 
   + updatedInvoiceList[0]);

Операция Upsert

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

пример

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

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

пример

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

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

// fetch the invoice created today
List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c,
createdDate FROM APEX_Invoice__c WHERE createdDate = today];
List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>();
APEX_Customer__c objCust = new APEX_Customer__C();
objCust.Name = 'Test';

// Inserting the Customer Records
insert objCust;
for (APEX_Invoice__c objInvoice: invoiceList) {
   if (objInvoice.APEX_Status__c == 'Pending') {
      objInvoice.APEX_Status__c = 'Paid';
      updatedInvoiceList.add(objInvoice);
   }
}

// DML Statement to update the invoice status
update updatedInvoiceList;

// Prints the value of updated invoices
System.debug('List has been updated and updated values are' + updatedInvoiceList);

// Inserting the New Records using insert DML statement
APEX_Invoice__c objNewInvoice = new APEX_Invoice__c();
objNewInvoice.APEX_Status__c = 'Pending';
objNewInvoice.APEX_Amount_Paid__c = 1000;
objNewInvoice.APEX_Customer__c = objCust.id;

// DML which is creating the new record
insert objNewInvoice;
System.debug('New Invoice Id is' + objNewInvoice.id);

// Deleting the Test invoices from Database
// fetch the invoices which are created for Testing, Select name which Customer Name
// is Test.
List<apex_invoice__c> invoiceListToDelete = [SELECT id FROM APEX_Invoice__c
   WHERE APEX_Customer__r.Name = 'Test'];

// DML Statement to delete the Invoices
delete invoiceListToDelete;
System.debug('Success, '+invoiceListToDelete.size()+' Records has been deleted');

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

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

пример

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

// fetch the invoice created today
List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c,
createdDate FROM APEX_Invoice__c WHERE createdDate = today];
List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>();
APEX_Customer__c objCust = new APEX_Customer__C();
objCust.Name = 'Test';

// Inserting the Customer Records
insert objCust;
for (APEX_Invoice__c objInvoice: invoiceList) {
   if (objInvoice.APEX_Status__c == 'Pending') {
      objInvoice.APEX_Status__c = 'Paid';
      updatedInvoiceList.add(objInvoice);
   }
}

// DML Statement to update the invoice status
update updatedInvoiceList;

// Prints the value of updated invoices
System.debug('List has been updated and updated values are' + updatedInvoiceList);

// Inserting the New Records using insert DML statement
APEX_Invoice__c objNewInvoice = new APEX_Invoice__c();
objNewInvoice.APEX_Status__c = 'Pending';
objNewInvoice.APEX_Amount_Paid__c = 1000;
objNewInvoice.APEX_Customer__c = objCust.id;

// DML which is creating the new record
insert objNewInvoice;
System.debug('New Invoice Id is '+objNewInvoice.id);

// Deleting the Test invoices from Database
// fetch the invoices which are created for Testing, Select name which Customer Name
// is Test.
List<apex_invoice__c> invoiceListToDelete = [SELECT id FROM APEX_Invoice__c
   WHERE APEX_Customer__r.Name = 'Test'];

// DML Statement to delete the Invoices
delete invoiceListToDelete;
system.debug('Deleted Record Count is ' + invoiceListToDelete.size());
System.debug('Success, '+invoiceListToDelete.size() + 'Records has been deleted');

// Restore the deleted records using undelete statement
undelete invoiceListToDelete;
System.debug('Undeleted Record count is '+invoiceListToDelete.size()+'. This should 
   be same as Deleted Record count');

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

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

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

DML заявления Методы базы данных
Частичное обновление не допускается. Например, если в списке 20 записей, либо все записи будут обновлены, либо ни одной. Частичное обновление разрешено. Вы можете указать параметр «Параметр в базе данных» как true или false, true, чтобы разрешить частичное обновление, и false, чтобы не разрешить то же самое.
Вы не можете получить список успешных и неудачных записей. Вы можете получить список успешных и неудачных записей, как мы видели в примере.
Пример — вставить listName Пример — Database.insert (listName, False), где false указывает, что частичное обновление не разрешено.

Операция вставки

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

пример

// Insert Operation Using Database methods
// Insert Customer Records First using simple DML Statement. This Customer Record will be
// used when we will create Invoice Records
APEX_Customer__c objCust = new APEX_Customer__C();
objCust.Name = 'Test';
insert objCust; // Inserting the Customer Records

// Insert Operation Using Database methods
APEX_Invoice__c objNewInvoice = new APEX_Invoice__c();
List<apex_invoice__c> InvoiceListToInsert = new List<apex_invoice__c>();
objNewInvoice.APEX_Status__c = 'Pending';
objNewInvoice.APEX_Customer__c = objCust.id;
objNewInvoice.APEX_Amount_Paid__c = 1000;
InvoiceListToInsert.add(objNewInvoice);
Database.SaveResult[] srList = Database.insert(InvoiceListToInsert, false);

// Database method to insert the records in List
// Iterate through each returned result by the method

for (Database.SaveResult sr : srList) {
   if (sr.isSuccess()) {
      // This condition will be executed for successful records and will fetch the ids 
      // of successful records
      System.debug('Successfully inserted Invoice. Invoice ID: ' + sr.getId());
      // Get the invoice id of inserted Account
   } else {
      // This condition will be executed for failed records
      for(Database.Error objErr : sr.getErrors()) {
         System.debug('The following error has occurred.');
         
         // Printing error message in Debug log
         System.debug(objErr.getStatusCode() + ': ' + objErr.getMessage());
         System.debug('Invoice oject field which are affected by the error:' 
            + objErr.getFields());
      }
   }
}

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

Давайте теперь рассмотрим наш пример бизнес-кейса с использованием методов базы данных. Предположим, нам нужно обновить поле состояния объекта Invoice, но в то же время нам также необходима такая информация, как состояние записей, идентификаторы неудачных записей, количество успешных операций и т. Д. Это невозможно при использовании операторов DML, поэтому мы должны использовать методы базы данных. чтобы получить статус нашей операции.

пример

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

Приведенный ниже код поможет обновить записи счетов-фактур с помощью метода Database.update. Кроме того, создайте запись Invoice перед выполнением этого кода.

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

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

Апекс — SOSL

У каждого бизнеса или приложения есть функциональность поиска как одно из основных требований. Для этого 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 в следующей главе.

Apex — SOQL

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

Как и SOSL, он не может выполнять поиск по нескольким объектам, но поддерживает вложенные запросы.

Пример SOQL

Рассмотрим наш постоянный пример химической компании. Предположим, нам нужен список записей, которые созданы сегодня и чье имя клиента не «test». В этом случае нам нужно будет использовать запрос 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, как показано ниже. Вы можете видеть, что родительская запись уже была назначена записи счета, как показано ниже.

Извлечение родительских записей SOQL

Извлечение записей о детях

Давайте теперь рассмотрим пример, в котором все счета, связанные с конкретной записью клиента, должны быть в одном месте. Для этого вы должны знать имя дочернего отношения. Чтобы увидеть имя дочернего отношения, перейдите на страницу сведений о поле дочернего объекта и проверьте значение «Дочерние отношения». В нашем примере это счета, добавленные __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 в конце поля Parent, а затем вы можете получить значение родительского поля.

Агрегатные функции

У SOQL есть агрегатная функция, как у нас в SQL. Агрегатные функции позволяют нам сворачивать и суммировать данные. Давайте теперь разберемся в функции подробно.

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

пример

// Getting Average of all the invoices for a Perticular Customer
AggregateResult[] groupedResults = [SELECT
   AVG(APEX_Amount_Paid__c)averageAmount FROM APEX_Invoice__c WHERE
   APEX_Customer__r.Name = 'ABC Customer'];
Object avgPaidAmount = groupedResults[0].get('averageAmount');
System.debug('Total Average Amount Received From Customer ABC is '+avgPaidAmount);

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

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

MIN () — это можно использовать, чтобы найти минимальное значение

MAX () — это можно использовать для поиска максимального значения.

Переменные вершины связывания

Вы можете использовать переменную Apex в запросе SOQL для получения желаемых результатов. На переменные Apex можно ссылаться с помощью двоеточия (:).

пример

// Apex 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 записей, по которым пользователь имеет доступ к.

пример

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

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

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

Шаг 1. В меню «Настройка» выберите «Разработка» → «Классы Apex».

Настройка Apex Cass Security Step1

Шаг 2 — Нажмите на название класса, который вы хотите ограничить. Мы нажали на CustomerOperationClass.

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

Шаг 3 — Нажмите на Безопасность.

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

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

Настройка безопасности класса Apex Шаг 3

Шаг 5 — Нажмите на Сохранить.

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

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

Настройка безопасности класса Apex из Permissionset Step1

Шаг 2 — Выберите набор разрешений.

Настройка безопасности класса Apex из Permissionset Step2

Шаг 3 — Нажмите на Доступ к классу Apex.

Настройка безопасности класса Apex из Permissionset Step3

Шаг 4 — Нажмите на Изменить.

Настройка безопасности класса Apex из Permissionset Step4

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

Настройка безопасности класса Apex из Permissionset Step5

Шаг 6 — Нажмите кнопку Сохранить.

Апекс — вызов

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

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

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

  • Асинхронная вершина

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

  • Класс веб-сервисов

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

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

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

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

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

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

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

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

Асинхронная вершина

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

Класс веб-сервисов

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

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

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

Apex Email Service для обработки входящей электронной почты

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

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

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

От выполнения анонимного блока

Вы можете вызвать класс Apex с помощью execute anonymous в консоли разработчика, как показано ниже —

Шаг 1 — Откройте консоль разработчика.

Шаг 2 — Нажмите на отладку.

Apex вызывает из анонимного шага Step1

Шаг 3 — Выполнить анонимное окно откроется, как показано ниже. Теперь нажмите на кнопку Выполнить —

Вызов Apex из Execute Anonymous Step2

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

Apex вызывает из анонимного шага Step3

Из триггера

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

Ниже приведен пример кода, который показывает, как класс выполняется при вызове Trigger.

пример

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

Apex Ivoking со страницы VF Step1

Код класса Apex (расширение контроллера)

Apex Ivoking From VF Page Step2

Апекс — Триггеры

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

Синтаксис

trigger triggerName on ObjectName (trigger_events) { Trigger_code_block }

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

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

  • вставить
  • Обновить
  • удалять
  • сливаться
  • upsert
  • восстановить

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

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

Шаг 1 — Перейти к sObject

Шаг 2 — Нажмите на клиента

Шаг 3 — Нажмите кнопку «Создать» в списке, связанном с триггером, и добавьте код триггера, как показано ниже.

// Trigger Code
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   List InvoiceList = new List();
   
   for (APEX_Customer__c objCustomer: Trigger.new) {
      
      if (objCustomer.APEX_Customer_Status__c == 'Active') {
         APEX_Invoice__c objInvoice = new APEX_Invoice__c();
         objInvoice.APEX_Status__c = 'Pending';
         InvoiceList.add(objInvoice);
      }
   }
   
   // DML to insert the Invoice List in SFDC
   insert InvoiceList;
}

объяснение

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

Существуют другие контекстные переменные, которые доступны в контексте — trigger.old, trigger.newMap, trigger.OldMap.

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

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

// Modified Trigger Code
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();
   
   for (APEX_Customer__c objCustomer: Trigger.new) {
      
      // condition to check the old value and new value
      if (objCustomer.APEX_Customer_Status__c == 'Active' &&
      
      trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
         APEX_Invoice__c objInvoice = new APEX_Invoice__c();
         objInvoice.APEX_Status__c = 'Pending';
         InvoiceList.add(objInvoice);
      }
   }
   
   // DML to insert the Invoice List in SFDC
   insert InvoiceList;
}

объяснение

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

Apex — триггерные шаблоны проектирования

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

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

Массовые шаблоны дизайна триггеров

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

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

// Bad Trigger Example
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   
   for (APEX_Customer__c objCustomer: Trigger.new) {
      
      if (objCustomer.APEX_Customer_Status__c == 'Active' && 
         trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
         
         // condition to check the old value and new value
         APEX_Invoice__c objInvoice = new APEX_Invoice__c();
         objInvoice.APEX_Status__c = 'Pending';
         insert objInvoice;   //DML to insert the Invoice List in SFDC
      }
   }
}

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

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

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

// Modified Trigger Code-Bulk Trigger
trigger Customer_After_Insert on APEX_Customer__c (after update) {
   List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();
   
   for (APEX_Customer__c objCustomer: Trigger.new) {
      
      if (objCustomer.APEX_Customer_Status__c == 'Active' &&
         trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
         
         //condition to check the old value and new value
         APEX_Invoice__c objInvoice = new APEX_Invoice__c();
         objInvoice.APEX_Status__c = 'Pending';
         InvoiceList.add(objInvoice);//Adding records to List
      }
   }
   
   insert InvoiceList;
   // DML to insert the Invoice List in SFDC, this list contains the all records 
   // which need to be modified and will fire only one DML
}

Этот триггер будет запускать только 1 оператор DML, так как он будет работать над списком, а список содержит все записи, которые необходимо изменить.

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

Trigger Helper Class

Написание всего кода в триггере также не является хорошей практикой. Следовательно, вы должны вызвать класс 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
   }
}

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

Один триггер на каждом объекте

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

Вы можете использовать контекстную переменную для вызова различных методов из вспомогательного класса согласно требованию. Рассмотрим наш предыдущий пример. Предположим, что наш метод createInvoice должен вызываться только при обновлении записи и при нескольких событиях. Тогда мы можем контролировать выполнение, как показано ниже —

// Trigger with Context variable for controlling the calling flow
trigger Customer_After_Insert on APEX_Customer__c (after update, after insert) {
   
   if (trigger.isAfter && trigger.isUpdate) {
      // This condition will check for trigger events using isAfter and isUpdate
      // context variable
      CustomerTriggerHelper.createInvoiceRecords(Trigger.new);
      
      // Trigger calls the helper class and does not have any code in Trigger
      // and this will be called only when trigger ids after update
   }
}

// Helper Class
public class CustomerTriggerHelper {
   
   //Method To Create Invoice Records
   public static void createInvoiceRecords (List<apex_customer__c> customerList) {
      
      for (APEX_Customer__c objCustomer: customerList) {
         
         if (objCustomer.APEX_Customer_Status__c == 'Active' &&
            trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
            
            // condition to check the old value and new value
            APEX_Invoice__c objInvoice = new APEX_Invoice__c();
            objInvoice.APEX_Status__c = 'Pending';
            InvoiceList.add(objInvoice);
         }
      }
      
      insert InvoiceList; // DML to insert the Invoice List in SFDC
   }
}

Apex — пределы правительства

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

Каковы пределы губернатора?

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

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

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

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

Как избежать SOQL Query Limit

Вы можете выполнить только 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. В этом случае запрос 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

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

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

Что такое пакетный апекс?

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

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

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

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

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

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

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

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

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

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

Мониторинг Apex Batch Step1

Мониторинг Apex Batch Step2

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

  • Начните
  • казнить
  • Конец

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

Начните

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

Синтаксис

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

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

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

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

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

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

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

казнить

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

Синтаксис

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

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

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

Конец

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

Синтаксис

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

Чтобы выполнить этот код, сначала сохраните его, а затем вставьте следующий код в «Выполнить анонимно». Это создаст объект класса, а метод Database.execute выполнит пакетное задание. Как только работа будет завершена, на указанный электронный адрес будет отправлено электронное письмо. Убедитесь, что у вас есть запись клиента, которая имеет Актив как проверено.

// Paste in Developer Console
CustomerProessingBatch objClass = new CustomerProessingBatch();
Database.executeBatch (objClass);

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

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

Ограничения

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

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

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

Шаг 1 — Перейдите к настройке ⇒ Apex Classes, нажмите на Apex Classes.

Планирование вершины со страницы сведений Step1

Шаг 2 — Нажмите на кнопку Schedule Apex.

Планирование вершины со страницы сведений Step2

Шаг 3 — Предоставьте детали.

Планирование вершины со страницы сведений Step3

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

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

// 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 — отладка

Отладка является важной частью любой разработки программного обеспечения. В Apex у нас есть определенные инструменты, которые можно использовать для отладки. Одним из них является метод system.debug (), который печатает значение и вывод переменной в журналах отладки.

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

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

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

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

пример

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

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

Шаг 1 — Откройте консоль разработчика

Шаг 2 — Откройте «Выполнить анонимно» в «Отладке», как показано ниже.

Открытая консоль разработчика для Class Eecution Step1

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

Открытая консоль разработчика для Class Eecution Step2

// Debugging The Apex
List<apex_customer__c> customerList = new List<apex_customer__c>();
customerList = [SELECT Id, Name FROM APEX_Customer__c WHERE CreatedDate =
today];
// Our Query
System.debug('Records on List are '+customerList+' And Records are '+customerList);
// Debug statement to check the value of List and Size

Шаг 4 — Откройте журналы, как показано ниже.

Отладка Apex Devconsole Step1

Шаг 5 — Введите «USER» в условиях фильтра, как показано ниже.

Шаг 6 — Откройте инструкцию USER DEBUG, как показано ниже.

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

Вы можете отлаживать тот же класс с помощью журналов отладки. Предположим, у вас есть триггер в объекте 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);
      }
   }
}

Следуйте приведенным ниже инструкциям для создания журналов отладки.

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

Отладка с помощью консоли отладки Step1

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

Отладка с помощью консоли отладки Step2

Отладка с помощью консоли отладки Step3

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

Отладка с помощью консоли отладки Step4

Шаг 4 — Измените записи клиента, так как должно произойти событие для создания журнала отладки.

Отладка с помощью консоли отладки Step5

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

Отладка с помощью консоли отладки Step6

Шаг 6 — Нажмите на ссылку просмотра первого журнала отладки.

Отладка с помощью консоли отладки Step7

Шаг 7 — Поиск строки «USER» с помощью поиска в браузере, как показано ниже.

Отладка с помощью консоли отладки Step8

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

Апекс — Тестирование

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

Тестовые занятия

В SFDC код должен иметь 75% покрытия кода для развертывания в Production. Это покрытие кода выполняется тестовыми классами. Тестовые классы — это фрагменты кода, которые тестируют функциональность другого класса Apex.

Давайте напишем тестовый класс для одного из наших кодов, который мы написали ранее. Мы напишем тестовый класс, чтобы покрыть наш код класса Trigger и Helper. Ниже приведен класс триггера и помощника, который необходимо охватить.

// 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 для проверки того же.

пример

/**
* This class contains unit tests for validating the behavior of Apex classes
* and triggers.
*
* Unit tests are class methods that verify whether a particular piece
* of code is working properly. Unit test methods take no arguments,
* commit no data to the database, and are flagged with the testMethod
* keyword in the method definition.
*
* All test methods in an organization are executed whenever Apex code is deployed
* to a production organization to confirm correctness, ensure code
* coverage, and prevent regressions. All Apex classes are
* required to have at least 75% code coverage in order to be deployed
* to a production organization. In addition, all triggers must have some code coverage.
*
* The @isTest class annotation indicates this class only contains test
* methods. Classes defined with the @isTest annotation do not count against
* the organization size limit for all Apex scripts.
*
* See the Apex Language Reference for more information about Testing and Code Coverage.
*/

@isTest
private class CustomerTriggerTestClass {
   static testMethod void myUnitTest() {
      //Create Data for Customer Objet
      APEX_Customer__c objCust = new APEX_Customer__c();
      objCust.Name = 'Test Customer';
      objCust.APEX_Customer_Status__c = 'Inactive';
      insert objCust;
      
      // Now, our trigger will fire on After update event so update the Records
      Test.startTest();    // Starts the scope of test
      objCust.APEX_Customer_Status__c = 'Active';
      update objCust;
      Test.stopTest();     // Ends the scope of test
      
      // Now check if it is giving desired results using system.assert
      // Statement.New invoice should be created
      List<apex_invoice__c> invList = [SELECT Id, APEX_Customer__c FROM
         APEX_Invoice__c WHERE APEX_Customer__c = :objCust.id];
      system.assertEquals(1,invList.size());
      // Check if one record is created in Invoivce sObject
   }
}

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

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

Шаг 1 — Перейдите в классы Apex ⇒ нажмите на название класса ‘CustomerTriggerTestClass’.

Шаг 2 — Нажмите кнопку Run Test, как показано.

Апекс Тестирование Шаг 1

Шаг 3 — Проверьте статус

Апекс Тестирование Шаг 2

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

Учебный класс

Апекс Тестирование Шаг 3

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

Апекс Тестирование Шаг 4

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

Апекс — Развертывание

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

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

Процесс развертывания

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

  • Force.com IDE
  • Изменить наборы
  • SOAP API
  • Force.com Migration Tool

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

Force.com Eclipse IDE

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

Eclipse Process Step1

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

Eclipse Process Step2

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

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

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

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

Шаг 1 — Зайдите в Setup и найдите «Deploy».

Шаг 2 — Нажмите «Исходящий набор изменений», чтобы создать набор изменений для развертывания.

Шаг 3 — Добавьте компоненты, чтобы изменить набор, используя кнопку «Добавить», затем «Сохранить» и нажмите «Загрузить».

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

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

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

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

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

Force.com Migration Tool

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