Приветствую!
Предположим, у вас есть задача построить динамический UI с полями или написать динамический SOQL запрос. В каждом из этих случаев нужно как-то реализовать возможность легкого добавления и удаления полей для отображения. Пример: у меня есть какая-то страница с набором полей, бизнесу нужно добавить ещё пару полей. Моя задача это сделать с минимальными затратами и максимально быстро. При этом я не хочу менять код решения и исправлять тесты для этого решения.
Как часто вы встречались с такой ситуаций?
В итоге вы начинаете работать над задачей и понимаете, что вам нужно создать доп хранилище под динамическую часть, где будет храниться какой-то более менее приемлемый интерфейс для редактирования этого списка полей. И как итог — задача обрастает таким количеством дополнительных подзадач, что может занять весьма большой отрезок времени.
FieldSet похож на page layout, однако без разделения на секции. В Fieldset могут входить любые поля: стандартные, кастомные, из установленных пакетов.
Field set можно создать для любого объекта.
Теперь мы, зная теоретическую часть, можем перейти к практике.
Создание FieldSet
FieldSet создается декларативным путем. Значит, мы можем легко это сделать через меню Setup. Для каждого объекта FieldSet создается отдельно. Единственное ограничение: fieldset можно создать лишь в Salesforce Classic, Lightning пока не поддерживается.
Путь для стандартных объектов
Setup -> Customize -> Object -> Field Sets
Путь для кастомных объектов
Setup -> Create-> Objects -> Object -> Field Sets
Далее мы создаем новый FieldSet и вносим необходимые данные, как на картинке ниже.
После чего мы попадаем в окно редактирования полей в FieldSet. Как вы можете заметить, эта форма очень похожа на page layout, однако имеет свои отличительные особенности. В данной форме нам интересна колонка In the FieldSet, в неё мы и будем добавлять наши поля.
Fieldset в Apex
Fieldsets легко можно использовать в Apex коде. Для этого у нас есть специальный системный класс Schema.FieldSet и ниже мы можем видеть пример его использования. В этом примере мы получаем коллекцию для sObject.
Map<String, Schema.FieldSet> FsMap = Schema.SObjectType.Account.fieldSets.getMap();
Однако, данный пример не самый оптимальный. В случае, если нам нужно получить один определенный FieldSet, мы можем использовать другой подход описанный в следующем примере.
Schema.FieldSet fs1 = Schema.SObjectType.Account.fieldSets.getMap().get('field_set_name');
Schema.FieldSet fs2 = Schema.SObjectType.Account.fieldSets.field_set_name;
В этом примере мы получаем данные определенного FieldSet для Account.
FieldSet и SOQL
Мы можем использовать FieldSet и для построения динамических SOQL запросов
String query = 'SELECT';
for(Schema.FieldSetMember fieldSet : SObjectType.Merchandise__c.FieldSets.Dimensions.getFields()) {
query += f.getFieldPath() + ', ';
}
query += 'Id, Name FROM Merchandise__c LIMIT 1';
List<Merchandise__c> merchandise = Database.query(query);
Таким образом мы можем получить гибкий и динамический SOQL запрос.
Fieldset и UI
Также мы можем использовать FieldSet для построения гибких интерфейсов. Давайте возьмем предыдущий пример и добавим визуальную часть.
Начнем с Apex класс:
public class MerchandiseDetails {
public Merchandise__c merch { get; set; }
public MerchandiseDetails() {
this.merch = getMerchandise();
}
public List<Schema.FieldSetMember> getFields() {
return SObjectType.Merchandise__c.FieldSets.Dimensions.getFields();
}
private Merchandise__c getMerchandise() {
String query = 'SELECT ';
for(Schema.FieldSetMember f : this.getFields()) {
query += f.getFieldPath() + ', ';
}
query += 'Id, Name FROM Merchandise__c LIMIT 1';
return Database.query(query);
}
}
Дальше добавим Visualforce страницу
<apex:page controller="MerchandiseDetails">
<apex:form >
<apex:pageBlock title="Product Details">
<apex:pageBlockSection title="Product">
<apex:inputField value="{!merch.Name}"/>
</apex:pageBlockSection>
<apex:pageBlockSection title="Dimensions">
<apex:repeat value="{!fields}" var="f">
<apex:inputField value="{!merch[f.fieldPath]}" required="{!OR(f.required, f.dbrequired)}"/>
</apex:repeat>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>
И по итогу у нас получается страница с динамическими полями, которые можно изменять максимально удобно и просто. А самое главное — не нужно создавать дополнительную сервисную логику и интерфейсы для работы этого решения.
Данный пример описывает решения на основе VisualForce страницах, однако FieldsSet также можно использовать и в LWC компонентах.