Map выступает типом данных, который сильно облегчит читаемость, эффективность и расширяемость вашего кода. Может быть применён множеством способов.
Надеюсь, что вы узнаете что-то новое, прочитав эту статью.
Инициализация Map
Тип Map имеет свою магию которая сделает ваш код более эффективным и читаемым.
Начнём со стандартного способа создания Map:
Map<Id, Account> accountsById = new Map<Id, Account>();
После создания мапы вы можете добавить значения с помощью метода put(). Однако, если у вас уже имеется List объектов, то можно просто передать коллекцию в конструктор.
Map<Id, Account> accountsById = new Map<Id, Account>(listOfAccounts);
Прелесть такого подхода в том, что он позволяет вам избежать итерации в цикле через весь лист. После передачи листа объектов Apex автоматически создаст набор ключей содержащих Id аккаунтов и сам аккаунт в качестве значения.
Такой подход поможет в случае, когда у нас есть триггер на аккаунте и нам нужно запросить для них контакты. Обычно приходиться идти через все аккаунты из Trigger.New и добавлять их id в Set. Но есть способ этого избежать:
Map<Id, Account> accountsById = new Map<Id, Account>(trigger.new);
Set<Id> accountIds = accountsById.keySet();
List<Contact> contacts = [SELECT Id, FirstName, LastName FROM Contact WHERE AccountId IN :accountIds];
Подсказка: если у вас есть лист объектов, то вам не нужно идти через всех чтобы получить id. Просто передайте этот лист объектов в запрос. Например у вас есть:
List <Account> accounts
И запрос будет иметь такой вид:
[SELECT Id FROM Contact WHERE AccountId IN :accounts]
Но что, если у вас нет листа с объектами для инициализации…
Тогда можно передать запрос сразу в map:
Map<Id, Account> accountsById = new Map<Id, Account>([SELECT Name FROM Account]);
В другом случае у вас может быть набор статичных переменных, которые нужно передать в map:
Map<string, string> stringMap = new Map<string, string>{ 'Key1' => 'Value1', 'Key2' => val2, key3 => val3};
Подход для запроса и хранения дочерних записей
Представим, что вам нужно написать триггер, который записывает некоторые значения в поля Opportunity, основываясь на значения, найденных в OpportunityLineItem
Теперь, с применением map, можно запросить все related записи для текущего листа opportunity. Затем организовать их в Map, где ключом будет opportunity Id и значением лист opportunity lime item, которые ассоциируются с этим opportunity Id.
Это будет иметь такой вид:
Set<Id> oppIds = trigger.newMap.keySet();
Map<Id, List<OpportunityLineItem>> lineItemsByOppId = Map<Id, List<OpportunityLineItem>>();
List<OpportunityLineItem> lineItems = queryOppLineItems(oppIds);
for (OpportunityLineItem lineItem : lineItems) {
if (lineItemsByOppId.containsKey(lineItem.OpportunityId)) {
lineItemsByOppId.get(lineItem.OpportunityId).add(lineItem);
}
else {
lineItemsByOppId.put(lineItem.OpportunityId, new List<OpportunityLineItem>{ lineItem });
}
}
for (Opportunity opp : trigger.new) {
if (lineItemsByOppId.containsKey(opp.Id)) {
List<OpportunityLineItem> oppLineItems = lineItemsByOppId.get(opp.Id);
for (OpportunityLineItem lineItem : oppLineItems) {
/*Do Something*/
}
}
}
Организация данных
Например, если ваша организация использует множество Record Type, и вам нужен доступ к ним, чтобы выполнять определённую логику. Вы можете просто запросить все типы и идти через цикл определять для каждой записи свои действия, основываясь на типе. Но что, если вам нужно сделать это более чем в методе или классе.
Используя такой подход, вы сможете хранить record type и использовать их в более удобной форме. Сделав всего 1 запрос, появиться возможность использовать эти записи в множестве блоков кода в течении 1 транзакции.
Map<string, Map<string, RecordType>> recordTypesByTypeAndName = new Map<string, Map<string, RecordType>>();
List<RecordType> recordTypes = [SELECT Id, Name, DeveloperName, SObjectType, IsActive FROM RecordType];
for (RecordType rt : recordTypes) {
if (recordTypesByTypeAndName.containsKey(rt.SObjectType)) {
Map<string, RecordType> recordTypeByName = recordTypesByTypeAndName.get(rt.SObjectType);
if (recordTypeByName.containsKey(rt.DeveloperName) == false) {
recordTypeByName.put(rt.DeveloperName, rt);
}
}
else {
recordTypesByTypeAndName.put(rt.SObjectType, new Map<string, RecordType>{ rt.DeveloperName => rt });
}
}
Ну и потом можно сделать helper метод, который поможет облегчить доступ к этим записям.
public Id getRecordTypeId(string objectType, string name) {
Id recordTypeId = null;
if (recordTypesByTypeAndName.containsKey(objectType)) {
Map<string, RecordType> recordTypesByName = recordTypesByTypeAndName.get(objectType);
if (recordTypesByName.containsKey(name)) {
RecordType rt = recordTypesByName.get(name);
recordTypeId = rt.Id;
}
}
return recordTypeId;
}
Надеюсь. Что статья была полезна! Пишите ваши вопросы и отзывы